The first time a function asks for a lifetime annotation, it can look as though Rust wants me to predict how long a value will live. That is not what the annotation does. It describes a relationship between references so the compiler can check that a returned borrow remains valid.
Most references need no written lifetime. A function with one borrowed input and one borrowed output, for example, usually gets that relationship through lifetime elision. The interesting cases are the ones where the signature leaves more than one possible source for the output.
Personal Note: I read
'aas “these borrows are connected,” not “keep this value alive for a long time.” That small change makes lifetime errors less mysterious to me.
Connect a Return Value to Its Inputs
This function may return either argument, so its signature must say that the returned reference is valid only while both possible inputs are available:
fn longer<'a>(left: &'a str, right: &'a str) -> &'a str { if left.len() >= right.len() { left } else { right }}
fn main() { let first = String::from("borrowed"); let second = String::from("data");
let chosen = longer(&first, &second); assert_eq!(chosen, "borrowed");}The function does not extend either input’s lifetime. It says the output cannot be used beyond the lifetime shared by the two input borrows. If one input goes away, the caller cannot keep using an output that might refer to it.
If a function always returns its first argument, the second argument does not need the same annotation. Annotate the references that actually participate in the relationship.
Store a Borrow in a Struct
A struct can also hold a reference, provided the struct cannot outlive the value it borrows:
struct Excerpt<'a> { text: &'a str,}
impl Excerpt<'_> { fn first_line(&self) -> &str { self.text.lines().next().unwrap_or("") }}
fn main() { let document = String::from("A short heading\nMore detail follows"); let excerpt = Excerpt { text: &document };
assert_eq!(excerpt.first_line(), "A short heading");}Excerpt borrows document; it does not own a copy. The lifetime parameter lets Rust reject an Excerpt that would remain in use after document is dropped.
Choose Ownership When It Fits Better
Lifetime annotations cannot make a reference to a local temporary safe to return. If callers need to keep a value independently, return an owned String or store one in the struct. Borrowing is useful when the data already has a clear owner and copying it would add unnecessary work.
When a lifetime error appears, I start by asking where the returned data comes from. Once the owner is clear, the signature usually follows.
Further Reading
- Validating References with Lifetimes in The Rust Programming Language
- References in the Rust Reference