Concept · Rust

Lifetimes

Annotations like 'a describe how long references stay valid and how outputs relate to inputs; they never extend anything's life.

3 min'a'staticlifetime elisiondoes not live long enough

A lifetime is the span of code during which a reference is valid. The compiler infers them inside function bodies. Across function boundaries it only reads signatures, so when a function returns a reference, the signature has to say which input it borrows from:

rust
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
    if a.len() >= b.len() { a } else { b }
}

Read it as: the result is valid as long as both inputs are. Callers can't use the result after either argument is dropped.

Elision: when you don't write them

Three rules fill in most lifetimes for you:

  1. Each reference parameter gets its own lifetime.
  2. If there's exactly one input lifetime, outputs get it.
  3. If there's &self or &mut self, outputs get its lifetime.

So fn trim(s: &str) -> &str and fn name(&self) -> &str need no annotations. You write them when there are several reference inputs, or when a method's result borrows from something other than self — the classic case is a parser struct whose tokens should borrow from the source text, not from the parser.

'static

&'static T is a reference valid for the whole program (string literals are &'static str). The bound T: 'static, which thread::spawn and tokio::spawn require, means something different: the type holds no borrowed data, so owned values like String satisfy it. Fix "borrowed value does not live long enough" in spawned work by moving owned data in or sharing it with Arc, not by annotating references 'static.

See the lifetimes lesson for structs that borrow and when to prefer owned data, and the borrow checker for the rule lifetimes serve.

Learn it in depth