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:
- Each reference parameter gets its own lifetime.
- If there's exactly one reference parameter, the output gets its lifetime. So
fn first_word(s: &str) -> &stris fine. - In methods with
&selfor&mut self, the output getsself's lifetime. Sofn name(&self) -> &stris fine.
E0106 means none of the rules applied, and you must say which input the output comes from.
Choosing the fix
- The result really points into one of the inputs: add
<'a>and tie the output to that input only (fn pick<'a>(a: &'a str, _b: &str) -> &'a str). - The function creates new data: return
String,Vec<T>or another owned type. - Adding
'staticeverywhere to silence the error is almost always wrong: it forces callers to pass literals or leaked data.
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