On-Ramp to Rust

lifetimes and the lifetime annotation

Every value in a Rust program exists for some span of time — created at one point, dropped at another. A lifetime is just a name for that span: the region of the program during which a particular value (and any reference borrowing it) is valid. The reason lifetimes matter is the one bug the borrow checker is most determined to prevent: a reference that outlives the thing it points to, which in C is a dangling pointer pointing at freed memory. A reference is only sound while the value it borrows is still alive, so the compiler has to reason about whose lifetime is longer.

Most of the time the compiler figures lifetimes out by itself and you never write one — it sees where values are created and dropped and where references are used, and quietly checks that no reference escapes its referent's lifetime. The lifetime annotation, written with a tick like 'a (read a tick a), appears only when the compiler cannot tell which input a returned reference came from. Consider a function that takes two string references and returns one of them: the compiler needs to know whether the returned reference borrows from the first argument or the second, so it knows how long the result is valid. You answer by naming a lifetime and tying the inputs and output together, for example fn longest<'a>(x: &'a str, y: &'a str) -> &'a str, which says all three share the lifetime 'a — the returned reference is valid only as long as both inputs are. The annotation does not change how long anything lives; it only describes the relationship so the borrow checker can verify it.

Why this matters and an honest caveat: lifetimes are how Rust guarantees, at compile time, the property C cannot — that you can never hold a reference into freed or out-of-scope memory. That is the dangling-reference bug class gone, with zero runtime cost. The honest part is that lifetime annotations are the feature beginners find most confusing, partly because the syntax is terse and partly because it is easy to think you are choosing how long something lives. You are not — you are only labelling spans that already exist so the compiler can match them up. The deep mechanics belong to a later volume; here the takeaway is simply that a lifetime is the span a value is valid, and a reference may never outlive it.

// 'a says: the returned reference lives as long as BOTH inputs do. fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }

The annotation describes which input the result borrows from; it does not extend any lifetime.

A lifetime annotation never makes a value live longer — it only states a relationship the borrow checker then verifies. If the relationship cannot hold, the fix is to restructure ownership, not to add more annotations.

Also called
lifetime'alifetime parameter生命週期生命週期參數