RustArena

Step 7 of 7

Reading lifetime errors

Lifetime errors look scary but come in a handful of shapes, and each shape has a short list of fixes. Here's the field guide.

Error What it means Usual fixes
E0106 missing lifetime specifier A signature or struct returns/holds a reference, and elision can't tell where from. Add 'a to tie the output to the right inputs; or return owned data; or 'static for literals.
E0597 x does not live long enough A value is dropped while a reference to it is still used later. Move the value to an outer scope; use the reference earlier; own the data.
E0515 cannot return reference to local variable A function returns a reference to something it created. Return the owned value (String, Vec).
E0716 temporary value dropped while borrowed You borrowed from a value that was never stored in a variable. Store it in a let first.
lifetime may not live long enough A function's body returns a reference with a different lifetime than its signature promised. Fix the signature (often rule 3 guessed self), or return what it promises.
E0499 / E0502 borrow conflicts Two borrows overlap (borrowing module). With methods: often a result tied to &mut self that should be tied to 'a. Shorter borrows; return &'a T from the data, not from self.

The temporary one deserves an example, because it surprises everyone once:

fn main() {
    let label = format!("v{}", 2).as_str();
    println!("{label}");
}
error[E0716]: temporary value dropped while borrowed
 --> src/main.rs:2:17
  |
2 |     let label = format!("v{}", 2).as_str();
  |                 ^^^^^^^^^^^^^^^^^         - temporary value is freed at the end of this statement
  |                 |
  |                 creates a temporary value which is freed while still in use
3 |     println!("{label}");
  |                ----- borrow later used here
  |
  = note: consider using a `let` binding to create a longer lived value

The String from format! has no owner variable, so it's dropped at the ;. The fix is in the note: give it an owner first (or just use the String).

fn main() {
    let owned = format!("v{}", 2);
    let label = owned.as_str();
    println!("{label}");
}
v2

A method for any lifetime error

  1. Find the value the error is about (the name in backticks).
  2. Find where it's dropped: the label dropped here while still borrowed, or the end of a function for E0515.
  3. Find the late use: borrow later used here.
  4. Pick a fix: make the owner live longer, end the use sooner, own the data, or (for signatures) describe the real relationship with 'a.

Resist adding annotations at random until it compiles. Each error describes a real dangling reference that would have crashed or corrupted data in C. Once you see which value would dangle, the fix is usually one line.

Your task

This program has three different lifetime errors (compile it to see them all). Fix each one in the way you think is best. The program must print:

winner: lifetimes
tag: #rust
version: v1.85

Challenge 2

Highlight marks a word inside a longer text without copying the text. The code is almost right, but the struct is missing its lifetime. Add the lifetime parameter to the struct and the impl block (and wherever else the compiler asks) so it prints:

the borrow [checker] is your friend
checker

Challenge 3

Starting from nothing, write a Sentences splitter in the style of the tokenizer from step 4:

For "Hi. How are you. Fine." the sentences are Hi, How are you and Fine. Text after the last . counts as a sentence too. The hidden tests collect every sentence into a Vec while calling next_sentence again, which only compiles if the sentences borrow from the text ('a), not from the splitter.

Previous: When to return owned data instead