Rust Trivia
What are the 3 types used to represent a sequence of values, and what are their generic type annotations?
- Array
[T; N]
- Vector
Vec<T>
- Slice
&[T]
How do you check the current size and capacity of any sequential-type value?
.len()
and.capacity()
What makes a
String
and a&str
unique? What are their effective underlying types?
- A
String
is just aVec<u8>
with the guarantee that the data is well-formed UTF-8.- A
&str
is just a slice&[u8]
of aString
.
Given
let x = y;
, under what condition would it be true thaty
did not become uninitialized?
If the type of
y
implements theCopy
trait.
Given
let s = "hello!";
, what is the type ofs
?
s
is a&str
whose pointer refers to preallocated, read-only memory on the stack.
How do you get the size of any data type?
std::mem::size_of::<T>();
What's a fat pointer?
A fat pointer is a pointer to a slice (a region of an array or vector). It's a two-word value on the stack comprised of:
- A pointer to the slice's first element
- The number of elements in the slice
What's the difference between
Arc
andRc
types?
Arc
(atomic reference count) is safe to share between threads directly, whereas aRc
uses faster non-thread-safe code to update its reference count.
When defining a type (
struct
), when is it required that a field's lifetime be specified?
Lifetimes must be specified when a field is a reference type. e.g.
struct RefPoint<'a, 'b> { x: &'a f64, y: &'b f64, }
What risk is sometimes posed by using reference count types?
If two
Rc
types point to each other, they will keep each other's ref count above zero and neither will be freed. This is called a reference cycle.
Given two reference variables
x
andy
, how do I check to see if they point to the same value in memory?
std::ptr::eq(x, y)
What are the two ways for closures to get data from enclosing scopes?
- Moves
- Borrowing
What are the three variants of
IntoIterator
implementations?
- Shared reference
- Mutable reference
- By value
When should you use either
Path
orOsStr
?
For absolute and relative paths, use
Path
. For an individual component of a path, useOsStr
.
How are
bool
values stored in memory, and why?
bool
values are stored as a whole byte so that pointers to them may be created.
What mechanism should you reach for to allow for shared ownership of a value?
Rc<T>
orArc<T>
(if sharing across multiple threads)
What mechanism allows us to mutate the value inside of an
Rc<T>
? What about anArc<T>
?
For an
Rc<T>
, interior mutability can be facilitated by aRefCell<T>
. For anArc<T>
, you'd reach for aMutex<T>
.
What special ability does a
Pin
'd object have?
Pinned (i.e. immovable) objects can have pointers to their own fields. e.g.
#![allow(unused)] fn main() { struct MyFuture { a: i32, ptr_to_a: *const i32, // I point to my own `a` } }
When would you use
ArcWake
(from thefutures
crate) trait?
Use
ArcWake
when you need an easy way to construct aWaker
.
What is the actual return type of this function?
#![allow(unused)] fn main() { async fn get_five() -> u8 { 5 } }
Returns value of type
impl Future<Output = u8>
.
How is an
async
function in terms of lifetimes if one of its arguments is a > reference or non-'static
value?
Unlike regular functions,
async
functions whose parameters are references or non-'static return aFuture
which is bounded by the lifetime of the arguments. Meaning, the future returned from anasync fn
must be.await
ed while its non-'static arguments are still valid.
What's the workaround for
async
functions' non-static lifetime rules?
An
async
function'sFuture
return value can be make'static
by moving the non-static (or reference) values into anasync
block:#![allow(unused)] fn main() { fn work_around() -> impl Future<Output = u8> { async { let x = 5; borrow_x(&x).await } } }
What's the formal fancy term to describe Rust's form of polymorphism?
What's the pattern used as a way to get around the orphan rule?
The newtype pattern, which involves creating a new type in a tuple struct.
I've implemented a newtype,
Wrapper
, that wraps aVec<T>
, but now I can't use theVec<T>
's built-in methods! What can I do?
Implement the
Deref
trait forWrapper
, which would allow us to treatWrapper
exactly like a Vec.
Something about how passing by value cedes all ownership of a value. Use
drop
as point of reference.
How do I write an
impl T
function that consumesT
(it will no longer be usable by others) and converts it toU
?
In the function's signature, you'd have
self
based by value, which will consume it. (usually, impl functions receive&self
)
How do I get the address of a value (say, a
String
)?
#![allow(unused)] fn main() { let txt = String::from("hello world"); let txt_stack = &txt as *const _; // Address of pointer on the stack let txt_heap = &txt.as_bytes()[0] as *const _; // Address of first charcacter in heap dbg!((txt_stack, txt_heap)); }
TODO: Go here and add stuff about the use of phantom/types/data