RustArena

Rust error E0106: missing lifetime specifier

How to fix Rust's E0106 missing lifetime specifier: adding <'a> to functions and structs, the elision rules, and when to return owned data.

E0106 appears when a function returns a reference, or a struct holds one, and the compiler can't tell which data the reference borrows from. It needs that to check that the reference never outlives the data. You answer with a lifetime parameter (a name like 'a), or by not returning a reference at all.

Case 1: two reference parameters, one returned reference

fn longest(a: &str, b: &str) -> &str {
    if a.len() >= b.len() { a } else { b }
}

fn main() {
    println!("{}", longest("arena", "crab"));
}
error[E0106]: missing lifetime specifier
 --> src/main.rs:1:33
  |
1 | fn longest(a: &str, b: &str) -> &str {
  |               ----     ----     ^ expected named lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
help: consider introducing a named lifetime parameter
  |
1 | fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
  |           ++++     ++          ++          ++

The suggested fix is right: fn longest<'a>(a: &'a str, b: &'a str) -> &'a str says "the result borrows from a or b, so it's only valid while both are". Annotations don't change how long anything lives; they describe the relationship so the compiler can check every caller.

Case 2: a struct that holds a reference

struct Excerpt {
    text: &str,
}

fn main() {
    let e = Excerpt { text: "call me Ferris" };
    println!("{}", e.text);
}
error[E0106]: missing lifetime specifier

Write struct Excerpt<'a> { text: &'a str }: an Excerpt can't outlive the text it points into. But first ask whether the struct should just own its data (text: String). For most structs (config, records, API types) owning is simpler. Reference-holding structs make sense for short-lived views: parsers, iterators, borrowed wrappers.

Case 3: returning a reference with nothing to borrow from

fn default_name() -> &str fails because there's no input to borrow from. rustc offers two fixes: &'static str if you return a string literal (literals live for the whole program), or, as it says, "instead, you are more likely to want to return an owned value": -> String.

When you don't need annotations: elision

Most functions with references need no lifetimes because of three elision rules:

  1. Each reference parameter gets its own lifetime.
  2. If there's exactly one reference parameter, the output gets its lifetime. So fn first_word(s: &str) -> &str is fine.
  3. In methods with &self or &mut self, the output gets self's lifetime. So fn name(&self) -> &str is fine.

E0106 means none of the rules applied, and you must say which input the output comes from.

Choosing the fix

Example

fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
    if a.len() >= b.len() { a } else { b }
}

fn first_word(s: &str) -> &str {
    s.split_whitespace().next().unwrap_or("")
}

fn default_name() -> &'static str {
    "guest"
}

fn shout(s: &str) -> String {
    s.to_uppercase()
}

struct Excerpt<'a> {
    text: &'a str,
}

impl<'a> Excerpt<'a> {
    fn first_sentence(&self) -> &'a str {
        self.text.split('.').next().unwrap_or(self.text)
    }
}

fn main() {
    println!("{}", longest("arena", "crab"));
    println!("{}", first_word("ownership rules everything"));
    println!("{}", default_name());
    println!("{}", shout("borrow checker"));

    let book = String::from("Call me Ferris. Some years ago I learned Rust.");
    let e = Excerpt { text: &book };
    println!("{}", e.first_sentence());
}

Output:

arena
ownership
guest
BORROW CHECKER
Call me Ferris

Practice it