Lifetimes
A reference must not outlive its data. You have been obeying that since borrows. This lesson is the syntax for the cases the compiler cannot infer, then the patterns that keep those annotations small. Closures come after, because they capture references and need this rule.
Naming a borrow
A lifetime is the region of code where a reference is valid. Most of them are inferred. You write one when a function returns a reference and the compiler cannot tell which input it came from. fn longest(x: &str, y: &str) -> &str fails for that reason. fn longest<'a>(x: &'a str, y: &'a str) -> &'a str says the result lives only as long as both inputs, which means as long as the shorter one.
&'a str on each parameter means neither borrow ends while 'a is still in use.
Elision is why many signatures need no annotation.
| Signature | Lifetime the compiler fills in |
|---|---|
| Each input reference | Its own lifetime |
| One input lifetime | That lifetime is used for the outputs |
A method with &self or &mut self | That lifetime is used for the outputs |
So fn first_word(s: &str) -> &str is already clear. 'static means the reference lives for the whole program: a string literal or a static. It does not mean “leak this.” Forcing 'static to silence an error usually hides the shorter lifetime you actually have. Prefer an owned String in a struct unless you are deliberately looking at a buffer without copying.
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
struct Excerpt<'a> {
part: &'a str,
}
fn main() {
let a = String::from("abcd");
let b = String::from("xyz");
let word = longest(&a, &b);
let excerpt = Excerpt { part: &a };
println!("{} {}", word, excerpt.part);
}Patterns
| Situation | What to do |
|---|---|
| A long-lived struct | Own the data. A borrowed field ties the struct to some other buffer. Zero-copy parsers do that on purpose, and only then. |
| You need to mutate the owner again | End the temporary borrow in a smaller block first. |
| The output might be either input | Give both inputs the same lifetime. |
| The output is always the first input | Name only that lifetime. |
| An erased error that crosses threads | Box of dyn Error plus Send plus Sync plus 'static. The error does not borrow a short-lived local. You will use it when you spawn work, not before. |
| A function that works for any lifetime | for<'a> Fn(&'a str) -> &'a str. You will see it on library signatures. You do not need to write it yet. |
struct User { name: String } can move freely. This is the default for domain types.
fn first_word(s: &str) -> &str {
s.split_whitespace().next().unwrap_or(s)
}
fn pick_first<'a>(primary: &'a str, _other: &str) -> &'a str {
primary
}
fn main() {
let sentence = String::from("hello rust");
let word = first_word(&sentence);
println!("{}", pick_first(word, "fallback"));
}