On this page
Lifetime
Lifetimes (
'a) are not runtime values—they are compile-time constraints on the valid scope of references. From elision rules (automatically inferred by the compiler) to explicit annotations (structs, variance, HRTBs), lifetime annotations essentially tell the borrow checker "which of these references outlives the others."
Lifetime is a Compile-Time Concept
Lifetime parameters ('a) are not runtime values—they are compile-time constraints: the valid scope of this reference cannot be longer than 'a. The compiler uses region inference in MIR to deduce the minimal lifetime.
Lifetime Elision
Most functions do not require explicit lifetime annotations—the compiler automatically infers them based on 3 rules:
- Each reference parameter without a lifetime annotation is assigned an independent lifetime (
fn foo<'a, 'b>(x: &'a T, y: &'b U)) - If there is only one input lifetime, it is assigned to all output lifetimes (
fn foo<'a>(x: &'a T) -> &'a U) - If there are multiple input lifetimes and one of them is
&selfor&mut self, theselflifetime is assigned to all outputs
Rule 2 is the most common: a single reference parameter → the returned reference defaults to borrowing that parameter. Rule 3 is why method chaining works: the borrow of self is passed to the return value.
Lifetime in Structs
When a struct contains references, you must explicitly annotate the lifetime:
The compiler's guarantee: an instance of Excerpt<'a> cannot outlive the referenced &'a str.
'static
'static is the only lifetime with a "special" meaning—it indicates that the referenced data lives for the entire duration of the program. Sources include:
- String literals: the type of
"hello"is&'static str—embedded in the binary at compile time, always valid Box::leak(Box::new(T))can produce&'static mut Tstaticvariables andconstreferences
Variance
Rust lifetimes have subtyping variance. Key rules to understand:
'long: 'short(meaning'longoutlives'short, so'longsatisfies the constraint of'short)&'a T: covariant in'a(if'long: 'short, then&'long Tcan be used where&'short Tis expected)&'a mut T: invariant in'a(you cannot shorten the lifetime of a mutable reference—otherwise it might violate the aliasing XOR mutation rule)
let mut x: &'static str = "hello";
// If this compiled, x would point to y's data → y gets dropped → dangling pointer
HRTB (Higher-Ranked Trait Bounds)
When a closure parameter has a lifetime but does not need to be explicitly declared:
// "f satisfies Fn(&'a str) -> &'a str for **any** lifetime 'a"
// No need to specify 'a at the call site—the compiler automatically quantifies it
PhantomData
When a struct has a lifetime but does not directly store a reference—use PhantomData to mark ownership/borrowing relationships:
use PhantomData;
References
- Rust Book: Chapter 10.3 — Validating References with Lifetimes
- Rust Reference: lifetime elision, variance
- RFC: RFC 2094 (NLL), RFC 387 (Higher-Ranked Trait Bounds)
Keywords: lifetime, elision, 'static, variance, covariant, invariant, HRTB, PhantomData, region inference