a lifetime parameter
/ 'a -> "tick-ay" /
Imagine you lend a friend a slip of paper with a locker number written on it. The slip is only useful while the locker is still rented; once the rental ends, the number points at an empty locker and following it is meaningless. A reference in Rust is exactly that slip: it is a borrow, an address that points at a value someone else owns. For the borrow to be safe, the value must outlive the slip. A lifetime parameter is how you write down, in a function or type signature, the relationship between how long several borrows are valid — so the compiler can check that no slip outlives its locker.
A lifetime is named with a tick and a short name, like 'a (read 'tick a'), and it is a generic parameter just like a type parameter T, except it stands for a span of code rather than a type. When you write fn longest<'a>(x: &'a str, y: &'a str) -> &'a str, you are telling the compiler: both inputs are borrows that live at least as long as some region 'a, and the returned borrow lives no longer than 'a either. The compiler does not pick 'a for you to make things work; it checks that whatever concrete region your callers actually supply, the returned reference never escapes it. The names 'a and 'b carry no meaning of their own — they are just labels that let you say 'this borrow and that borrow share a lifetime' or 'this output borrows from that input, not the other one'. There is one built-in name, 'static, meaning a borrow valid for the entire run of the program (a string literal is &'static str).
Why this matters: lifetime parameters are not instructions that change what the code does — they add no runtime cost and produce no code at all. They are constraints you state so the borrow checker can prove, at compile time, that every reference points at living memory. The common beginner misconception is that 'a sets or controls how long a value lives; it does not. The value's life is fixed by ownership and scope; 'a merely describes and relates borrows of it so the checker can reject the ones that would dangle. You only have to write them when the compiler cannot infer the relationship on its own — most of the time the elision rules fill them in.
// 'a says: the returned borrow lives no longer than BOTH inputs. fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } } let r; { let s = String::from("short-lived"); r = longest("long literal", &s); // r would borrow from s... } // s dropped here // println!("{r}"); // error[E0597]: `s` does not live long enough
'a does not extend any value's life; it lets the compiler reject a borrow that would outlive what it points at.
Lifetime parameters describe borrows, not data. Writing 'a never makes a value live longer; it only states a constraint the borrow checker then verifies. Forgetting this is the single most common confusion when first reading lifetime signatures.