Rust Lifetimes
Lifetimes are usually the point where new Rust developers hit their first real wall. This page keeps things gentle — the goal is just to recognize what a lifetime is and why the compiler asks for one, not to master every rule around them.
The problem lifetimes solve
Section titled “The problem lifetimes solve”You already know from borrowing that a reference (&) lets you use a value without owning it. But a reference is only valid as long as the value it points to still exists. Rust needs to make sure you never end up with a reference to something that’s already been cleaned up — that class of bug is called a dangling reference, and it’s a classic source of crashes in languages like C.
Most of the time, Rust figures this out on its own by looking at your code’s scopes — you never have to think about it (this is exactly what you saw on the Scope page). But sometimes, especially with functions, the compiler can’t work it out by itself and asks you to spell it out. That’s what a lifetime annotation is.
A function where Rust needs help
Section titled “A function where Rust needs help”Here’s a function that returns the longer of two string slices:
fn longest(a: &str, b: &str) -> &str { if a.len() > b.len() { a } else { b }}This won’t compile. The error looks like:
error[E0106]: missing lifetime specifierThe problem: the returned reference could be borrowed from a or from b, and Rust can’t tell which one just by reading the function — so it can’t guarantee the reference you get back is still valid by the time you use it.
Adding a lifetime annotation
Section titled “Adding a lifetime annotation”You fix it by naming a lifetime (by convention, a lowercase letter like 'a) and telling Rust that the return value’s lifetime is tied to both parameters:
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str { if a.len() > b.len() { a } else { b }}
fn main() { let s1 = String::from("hello"); let s2 = String::from("hi");
let result = longest(&s1, &s2); println!("Longest: {result}");}Output:
Longest: helloRead 'a as a label, not a value — it doesn’t set an actual duration. It just tells Rust “these references all need to stay valid for at least the same stretch of code.” The compiler then checks every call site to make sure that’s actually true.
Why this matters
Section titled “Why this matters”Without this annotation, the compiler genuinely can’t tell whether the reference longest hands back might outlive one of the strings it came from. The lifetime annotation is what lets it prove — at compile time, with zero runtime cost — that the reference you get back will always be valid to use.
The good news
Section titled “The good news”You’ll write 'a far less often than this page might suggest. Plenty of Rust code never needs an explicit lifetime, because the compiler can infer them in most everyday situations. You mainly run into them when a function returns a reference and the compiler can’t work out on its own where it came from — at that point, just remember: it’s not a bug, it’s the compiler asking you to confirm something it can’t prove by itself.
- A lifetime tells the compiler how references relate to each other so it can rule out dangling references.
- You only need to write one when the compiler can’t infer it on its own — most commonly, functions that return a reference.
'adoesn’t set a duration — it links the lifetimes of different references so the compiler can check them.- This is entirely a compile-time check; it adds no runtime cost.