🎓 A1Learner
🔍

Rust Lifetimes

A lifetime is the stretch of time a reference stays valid. A lifetime annotation names that stretch in a signature.

A lifetime is written with a quote

'a is read as "lifetime a", and &'a str means: a reference that lives for lifetime a. Here one name ties two inputs and the output together:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str

The result lives as long as the shorter input

longest promises one thing. The result lives as long as the shorter of the two inputs. So it can never point at freed text:

let result = longest("abcd", "xy");
println!("longest = {}", result);

'static lives for the whole program

'static means: the value lives for the whole program. Text written directly in code is like this:

let greeting: &'static str = "hello";
println!("{}", greeting);

A struct holding a reference names it too

A struct that holds a reference names the lifetime, so the struct can never outlive the text it points at:

struct Excerpt<'a> { text: &'a str }
let excerpt = Excerpt { text: "Call me Ishmael." };
println!("{}", excerpt.text);

A returned reference must be tied to an input

This function builds a String inside itself and tries to return a reference to it. That is error E0515, and no annotation can fix it — return an owned value instead:

fn dangling<'a>() -> &'a str {
    let s = String::from("hello");
    &s
}

Inputs may carry different lifetimes

Two inputs may use two different names, promising nothing between them. A short lifetime can never be stretched into a longer one — pretending otherwise fails with error E0597:

fn print_refs<'a, 'b>(x: &'a i32, y: &'b i32) {
    println!("{} and {}", x, y);
}
let a = 10;
let b = 20;
print_refs(&a, &b);

Example

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
fn main() {
    let result = longest("long string", "short");
    println!("longest = {}", result);
}

Key points

  • Most signatures need no annotations at all — Rust guesses by fixed rules, called elision
  • Lifetimes, types and bounds can share one signature.
  • Here is one: fn longest_with_note<'a, T: Display>(x: &'a str, y: &'a str, note: T) -> &'a str.
  • A lifetime is not a scope.
  • A scope is the block of text where a name lives.
  • A lifetime is the stretch during which a reference stays valid.
  • Rust works it out from where the reference is used.

In this example, longest takes two text references and returns the longer one. Both inputs and the output share the lifetime 'a. That is a promise. The returned reference is valid only while both inputs are valid. So it can never point at freed text. "long string" has 11 characters and "short" has 5, so the function returns the first one. The println! shows longest = long string.

Note

A lifetime annotation does not make anything live longer.

It only describes a relationship that is already true, so the compiler can check it.

If the compiler reports a lifetime error, it found a reference that could truly dangle.

Restructure the code.

Do not fight the checker.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

What does 'static mean as a lifetime?