Lifetime elision rules help Rust understand how long references live without you writing extra code. This makes your code simpler and easier to read.
Lifetime elision rules in Rust
fn function_name(&self, param: &Type) -> &Type {
// function body
}Rust applies three main lifetime elision rules automatically.
You only need to write lifetime annotations if Rust cannot figure them out from these rules.
fn first_word(s: &str) -> &str {
// returns a slice of the input string
}fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
impl<'a> ImportantExcerpt<'a> { fn level(&self) -> i32 { 3 } }
This program shows a struct holding a reference with a lifetime. The method uses lifetime elision rules so we don't write lifetimes on &self, the parameter, or the return type.
struct ImportantExcerpt<'a> { part: &'a str, } impl<'a> ImportantExcerpt<'a> { // Method with elided lifetimes fn announce_and_return_part(&self, announcement: &str) -> &str { println!("Announcement: {}", announcement); self.part } } fn main() { let text = String::from("Rust is awesome!"); let excerpt = ImportantExcerpt { part: &text[0..4] }; let announcement = "Here is an important part:"; let result = excerpt.announce_and_return_part(announcement); println!("Returned part: {}", result); }
Time complexity: Lifetime elision does not affect runtime; it is a compile-time feature.
Space complexity: No impact on memory usage.
Common mistake: Expecting Rust to always guess lifetimes; sometimes you must write them explicitly.
When to use: Use elision to keep code clean, but add explicit lifetimes when Rust cannot infer them.
Lifetime elision rules let Rust fill in lifetimes automatically in common cases.
There are three main rules that Rust follows to guess lifetimes.
Use explicit lifetimes only when Rust cannot figure them out on its own.
Practice
Solution
Step 1: Understand lifetime elision rules
Lifetime elision rules help Rust guess lifetimes automatically in common cases.Step 2: Compare options
Only To let Rust automatically fill in lifetimes in common cases without explicit annotations. correctly states that Rust fills in lifetimes automatically without needing explicit annotations in many cases.Final Answer:
To let Rust automatically fill in lifetimes in common cases without explicit annotations. -> Option AQuick Check:
Lifetime elision = automatic lifetime filling [OK]
- Thinking Rust always requires explicit lifetimes
- Believing lifetimes are removed entirely
- Assuming Rust ignores lifetime errors
Solution
Step 1: Recall lifetime elision rules for functions
When a function has one input lifetime, Rust assumes the output lifetime is the same as the input.Step 2: Analyze options
fn first_word(s: &str) -> &str uses no explicit lifetimes but is valid due to elision. fn first_word<'a>(s: &'a str) -> &'a str is explicit but correct. fn first_word(s: &str) -> &'a str is invalid because it uses an undefined lifetime in output. fn first_word<'a>(s: &str) -> &str mixes explicit and implicit lifetimes incorrectly.Final Answer:
fn first_word(s: &str) -> &str -> Option BQuick Check:
One input ref means output ref gets same lifetime [OK]
- Using undefined lifetime parameters
- Mixing explicit and implicit lifetimes incorrectly
- Forgetting elision rules allow omission
fn longest(x: &str, y: &str) -> &str {
x
}
fn main() {
let string1 = String::from("apple");
let string2 = String::from("banana");
let result = longest(&string1, &string2);
println!("Longest string is: {}", result);
}Solution
Step 1: Check lifetime elision rules for the function
The function takes two input references (x and y) and returns a reference. Elision rules do not apply when there are multiple input lifetimes and an output lifetime; Rust cannot determine which input lifetime to use for the output.Step 2: Confirm compilation behavior
This results in a compilation error: `missing lifetime specifier`. The code does not compile.Final Answer:
Compilation error due to missing lifetime annotations -> Option DQuick Check:
Multiple input refs need explicit lifetimes [OK]
- Thinking elision allows compilation with multiple input refs
- Believing it returns the longer string
- Confusing runtime errors with lifetime errors
fn invalid_ref(x: &str, y: &str) -> &str {
let result = String::from("hello");
&result
}Solution
Step 1: Analyze the returned reference
The function returns a reference to 'result', a local String created inside the function.Step 2: Understand lifetime rules and error
'result' is dropped when the function ends, so returning a reference to it causes a dangling reference error.Final Answer:
The function returns a reference to a local variable that will be dropped. -> Option AQuick Check:
Returning local reference causes dangling pointer [OK]
- Thinking missing lifetime annotations cause this error
- Believing explicit lifetimes fix dangling references
- Confusing return type with ownership
struct Container<'a> {
value: &'a str,
}
impl<'a> Container<'a> {
fn get_value(&self) -> &str {
self.value
}
}
What lifetime does Rust assign to the return value of get_value by elision?Solution
Step 1: Identify lifetime elision rules for methods
Rule 3 states that if there is a &self or &mut self parameter, the output lifetime is the same as self's lifetime.Step 2: Apply rule to method signature
The method takes &self and returns &str without explicit lifetime. Rust assigns the return lifetime to match &self's lifetime.Final Answer:
The return value has the same lifetime as &self (the method receiver). -> Option CQuick Check:
Method output lifetime = &self lifetime [OK]
- Confusing struct lifetime with method output lifetime
- Assuming static lifetime without reason
- Ignoring elision rule for &self receiver
Ready to prove it?
Pass the test and this pattern moves unknown
