Lifetimes Flashcards
What is lifetime in rust? Who ensures that all references have valid lifetimes?
The duration in which a reference to some value may exist.
The rust compilers ensures all references have valid lifetimes.
What is the definition of concrete lifetime for a value?
In Rust, a value’s lifetime is the time during which the value exists at a particular memory address.
Start: created or moved into a location in memory
End: moved or dropped from that location
What is the extra constraint of concrete lifetime for a reference?
(References are values so the definition of start and end are the same as for values)
Additionally, a reference’s lifetime must be contained within the referenced value’s lifetime (ensures every reference is valid)
What crates can be used to enable self-referential structs?
The crates are: rental, owning-ref
use unsafe code, but expose safe wrapper to manage self-referential structs.
What is a “generic lifetime”?
A generic lifetime is the lifetime of a reference in code, where we can’t know all of the possible concrete lifetimes of the values being referenced at compile time.
Where can generic lifetimes exist?
Generic lifetimes can exist in the definitions of functions, methods, structs, enums, and traits.
What are the implicit lifetime annotation in the following functions? what is Rust assumption? fn return_first_two(borrowed_list: &[i32]) -> &[i32] { &borrowed_list[0..2] }
The only way in which a function can return a reference is that it gets a value to reference in the input. Rust assumptions are embodied in the following lifetime notations: fn return_first_two(borrowed_list: &'a [i32]) -> &'a [i32] { &borrowed_list[0..2] }
Add appropriate generic lifetime notations: fn simulate_game(home: &str, away: &str) -> &str { if rand::random() { home } else { away } }
fn simulate_game(home: &'a str, away: &'a str) -> &'a str {...}
*the reference returned is tied to the lifetime of both input parameters
Add appropriate generic lifetime notations:
fn stem(&self, word: &str) -> &str {
if word.ends_with(&self.suffix) {
let index = word
.rfind(&self.suffix)
.expect(“found b.c. ends_with returned true”);
&word[0..index]
} else {
word
}
}
fn stem(&self, word: &'a str) -> &'a str {...} or fn stem(&'a self, word: &'b str) -> &'b str {...}
*The reference returned is tied to the lifetime of the word parameter.
Create a generic struct named “Approval”, with a generic field named “item” and a boolean field named “approved”
struct Approval {
item: T,
approved: bool,
};
Implement a constructor for a generic named “Approval”, with a generic field “item” and a boolean field “approved”. The constructor will get an item and will set “approved” to false.
impl Approval { pub fn new(item: T) -> Approval { Approval {item: item, approved: false} } }
What is the purpose of generic lifetime parameters?
The purpose of generic lifetime parameters is to tell the compiler how the lifetimes of references are related. Once the compiler knows about the relationships that references have, it has enough information to check that all references will always be valid.
How do you pronouce ‘a?
“tic a”
Write the signature of a function “foo” that uses the time annotation ‘a and the generic type T, has a parameter bar of type T with life time ‘a and returns a reference to the type T.
fn foo(bar: ‘a T) -> &’a T {…}
Explain what is the meaning of Generic over types VS Generic over scopes?
eneric type parameters are generic over types. They allow you to write code once that works with many different types. Generic lifetime parameters are generic over scopes. They allow you to write code once that works with many different references that are valid for different lengths of time.