Lifetimes Flashcards

1
Q

What is lifetime in rust? Who ensures that all references have valid lifetimes?

A

The duration in which a reference to some value may exist.

The rust compilers ensures all references have valid lifetimes.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What is the definition of concrete lifetime for a value?

A

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

What is the extra constraint of concrete lifetime for a reference?

A

(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)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What crates can be used to enable self-referential structs?

A

The crates are: rental, owning-ref

use unsafe code, but expose safe wrapper to manage self-referential structs.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

What is a “generic lifetime”?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Where can generic lifetimes exist?

A

Generic lifetimes can exist in the definitions of functions, methods, structs, enums, and traits.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q
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]
}
A
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]
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q
Add appropriate generic lifetime notations:
fn simulate_game(home: &str, away: &str) -> &str {
    if rand::random() {
        home
    } else {
        away
    }
}
A
fn simulate_game(home: &'a str, away: &'a str) 
-> &'a str {...}

*the reference returned is tied to the lifetime of both input parameters

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

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
}
}

A
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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Create a generic struct named “Approval”, with a generic field named “item” and a boolean field named “approved”

A

struct Approval {
item: T,
approved: bool,
};

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

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.

A
impl Approval {
  pub fn new(item: T) -> Approval {
    Approval {item: item, approved: false}
  }
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What is the purpose of generic lifetime parameters?

A

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 well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

How do you pronouce ‘a?

A

“tic a”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

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.

A

fn foo(bar: ‘a T) -> &’a T {…}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Explain what is the meaning of Generic over types VS Generic over scopes?

A

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

The names of generic type parameters should be in…

A

upper camel case

17
Q

The names of generic lifetime parameters should be in…

A

snake case

18
Q

When using generic types, Rust generates…

A

When using generic types, Rust generates code for each of the types that the generic code is called with.

19
Q

Does the compiler generates any additional code due to generic lifetime annotations?

A

No.

Generic lifetime parameters only assist with analysis and are then discarded.

20
Q

What is the ‘static lifetime?

A

The ‘static lifetime is a concrete lifetime - the only concrete lifetime you can specify in code. The ‘static lifetime is for references that are valid the entire time your program is running.

21
Q

Why aren’t lifetime parameters prescriptive?

A

Lifetime parameters don’t prescribe, by which we mean they don’t order code to behave a
certain way. They don’t specify how long a concrete lifetime of a value or a reference must
be. They don’t change the concrete lifetimes of values or references. Lifetime parameters
aren’t setting lifetimes, assigning lifetimes, or forcing lifetimes to be a certain length.
And adding lifetime parameters won’t make a reference live long enough to be valid for that
code.

22
Q

Why aren’t lifetime parameters prescriptive?

A

Lifetime parameters don’t prescribe, by which we mean they don’t order code to behave a
certain way. They don’t specify how long a concrete lifetime of a value or a reference must
be. They don’t change the concrete lifetimes of values or references. Lifetime parameters
aren’t setting lifetimes, assigning lifetimes, or forcing lifetimes to be a certain length.
And adding lifetime parameters won’t make a reference live long enough to be valid for that
code.

23
Q
Add a lifetime annotation to make the following function valid. What can we say about the returned type?
fn return_first_two() -> &[i32] {
  &LIST[0..2]
}
A
Must add the static lifetime annotation in this case, and make sure LIST is a static variable:
static LIST: [i32; 3] = [1, 2, 3];
fn return_first_two() -> &'static[i32] {
  &LIST[0..2]
}
24
Q

What is lifetime elision?

A

Set of rules, programmed in Rust’s compiler, that were added so that programmers won’t have to add generic lifetime parameters on every reference.
If rules aren’t enough to figure out lifetime parameters, compiler will error.

25
Q
Add the implicit lifetimes in the following code. Does it compile?
fn ex(amt: i32, name: &str, user: &User) -> &str
A

fn ex(amt: i32, name: &’a str, user: &’b User) -> &str

  • In parameters, each reference gets its own lifetime.
  • Doesn’t compile because we must anotate the returned value ourselves.
26
Q
Add the implicit lifetimes in the following code. Does it compile?
fn ex(color_name: &str, saturation: u8) -> &Color
A

fn ex(color_name: &’a str, saturation: u8) -> &’a Color

  • If there is only one lifetime in the parameters, returned reference gets that lifetime
  • Compiles
27
Q
Add implicit lifetimes in the following code. Does it compile?
struct Config { 
version: usize, settings: HashMap,}
impl Config {
  fn get_value(&self, key: &str) -> &str {}
}
A

fn get_value(&’a self, key: &’b str) -> &’a str {}

  • If there is a &self or &mut self paramer, returned reference gets that lifetime
  • Compiles