user855
user855

Reputation: 19938

Does a lifetime specified on a reference represent how long the reference or the object is going to live?

pub struct Foo<'m, T> {
    tx: &'m mut T,
}

Here, is 'm representing the lifetime of the reference tx or is it specifying how long the T is going to last?

I believe that it's the former and it means the lifetime of the object of type T that tx is referring to must exceed 'm. Is this the correct understanding?

Upvotes: 0

Views: 371

Answers (2)

Shepmaster
Shepmaster

Reputation: 431589

&'a T means "I know that a valid value of type T exists at the address contained in this reference for at least as long as the region of code demarcated by 'a".


The full answer depends on:

  1. what you think "live" and "lifetime" mean
  2. what you mean by "lifetime of the reference"

As stated in Why can't I store a value and a reference to that value in the same struct?, the "lifetime" of a value is not what most people expect:

As an analogy, think of it this way: During a person's life, they will reside in many different locations, each with a distinct address. A Rust lifetime is concerned with the address you currently reside at, not about whenever you will die in the future (although dying also changes your address). Every time you move it's relevant because your address is no longer valid.

A non-reference value has one or more lifetimes associated with it between when it is created and when it is destroyed, but on a single line of code it has only one that is relevant.

A reference has two lifetimes associated with it on a single line of code:

  1. How long the reference value itself is valid at the current memory address.
  2. How long the referred-to value is valid at its current memory address.

Here, the concrete lifetime of a is [0, 2]. The concrete lifetime of b is [1, 2]. Since b refers to a, that's also a related lifetime:

fn example() {
    let a = 42;               // 0  A
    let b = &a;               // 1  |  B
    println!("{}, {}", a, b); // 2  |  |
}

As the reference depth increases, this continues — &&&&i32 has five associated lifetimes.

Most of the time, this doesn't matter because the compiler will automatically collapse lifetimes... when variance allows for it.

Additionally, since your example uses generic types, it's effectively expanded to:

pub struct Foo<'m, T: 'm> {
    tx: &'m mut T,
}

That is, if the generic type T contains any references, they must equal or outlive the lifetime 'm.

See also:

Upvotes: 1

Aplet123
Aplet123

Reputation: 35560

You are correct: 'm is the lifetime of the reference. And, since the reference must live to be valid for 'm, the object it's referencing must live at least as long as 'm. You can see this in the compiler errors:

This code that tries to create a 'static reference from a temporary string:

fn main() {
    let x: &'static String = &"foo".to_string();
}

errors since the string doesn't live as long as the reference:

error[E0716]: temporary value dropped while borrowed
 --> src/main.rs:2:31
  |
2 |     let x: &'static String = &"foo".to_string();
  |            ---------------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
  |            |
  |            type annotation requires that borrow lasts for `'static`
3 | }
  | - temporary value is freed at the end of this statement

A lifetime on the object itself would be denoted with the lifetime in a generic syntax:

pub struct Foo<'a> {
    slice_iter: std::slice::Iter<'a, u32>
}

Upvotes: 0

Related Questions