Recipe
Fix a lifetime error
Use when: rustc reports E0597, E0515, E0716 or E0499 around a borrow, or says a lifetime may not live long enough, and you're tempted to add or change annotations
Goal: a program whose ownership really keeps every reference valid, with a signature that says only what's true
Taught in Common lifetime errors
Quick recipe
-
1
Read the error's labels: which value is borrowed, where it's dropped, and where the late use is.
Example
In the quotes program, rustc's E0597 has three labels.
lineis borrowed on line 11, byline.split_once(": "). It is dropped on line 14, the loop's closing}. The late use is"eson line 15. So eachQuotepoints into alinethat is gone before the quotes are printed.Why: every lifetime error is a reference that would outlive its value, or a claim that it could; you need both ends before choosing a fix.
-
2
Decide who should own the data for as long as it's needed.
Example
This is E0597, and
linedies at the end of each loop pass. Move the owner outward: before the loop, buildlet lines: Vec<String> = raw.iter().map(|r| r.to_uppercase()).collect();, then loop withfor line in &lines. The text now lives until the end ofmain, and the program printsANN said WE SAIL AT DAWN.- the data was created inside a function (E0515) — return it owned.
- the data is a temporary (E0716) — give it a name with let.
- the data dies each loop pass or in an inner block (E0597) — own a copy, move the owner outward, or use the reference sooner.
Why: lifetimes never extend anything, so the only real fixes change ownership, placement, or the uses.
-
3
If the error is inside a function body, or calls are rejected that should work, compare each
'awith what the body really returns.Example
Words::next_word(&'a mut self) -> Option<&'a str>compiles, but two calls in a row give E0499. The body returns a slice of the text, not ofself. So the'aonselfsays something untrue. Remove it:fn next_word(&mut self) -> Option<&'a str>. Both calls now work, and the program printsSome("north") Some("by").- an input tied to the output that is never returned — remove its 'a.
- &'a mut self on a type with lifetime 'a — use &mut self.
Why: an annotation that claims too much makes correct calls fail; one that claims too little makes the body fail.
-
4
Add or change annotations only to state a relationship the code already has (section 2's recipe).
Example
fn normalized(name: &str) -> &strreturns&lower, a newString, and gets E0515. Writingfn normalized<'a>(name: &'a str) -> &'a strchanges nothing: still E0515. The result is not a piece ofname, so there is no true relationship to write down. Step 2's fix is the real one: returnString.Why: an annotation added to silence an error either moves the error elsewhere or makes the function uncallable.
Common mistakes
- Adding
'staticbecause rustc mentioned it. - Adding
'ato more parameters until the error moves. - Cloning inside a function to dodge an error at a call site, when the call site is what's wrong.