Bird
Raised Fist0
Rustprogramming~10 mins

Lifetime elision rules in Rust - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Lifetime elision rules
Start: Function with references
↓
Check input lifetimes
↓
Apply Rule 1: One input ref?
| Yes↓
Output lifetime = input lifetime
No↓
Apply Rule 2: Multiple input refs, one &self or &mut self?
| Yes↓
Output lifetime = self's lifetime
No↓
Apply Rule 3: Multiple input refs, no self
↓
Output lifetime = anonymous, compiler error if ambiguous
↓
End
The compiler applies three rules to assign lifetimes to references in functions without explicit annotations, simplifying code while ensuring safety.
Execution Sample
Rust
fn first_word(s: &str) -> &str {
    &s[0..1]
}
A function taking one reference input and returning a reference with the same lifetime, using Rule 1.
Execution Table
StepInput ReferencesRule AppliedOutput LifetimeExplanation
1&str sRule 1Same as sOne input reference, output lifetime matches input
2&self, &str sRule 2Same as selfMultiple inputs including &self, output lifetime matches self
3&str s1, &str s2Rule 3Compiler error if ambiguousMultiple inputs, no self, output lifetime ambiguous
4No referencesNo ruleNo lifetime neededNo references, no lifetime elision needed
💡 Lifetime elision rules stop after applying the first matching rule or error if ambiguous
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 3Final
Input referencesNone&str s&self, &str s&str s1, &str s2N/A
Output lifetimeNoneSame as sSame as selfAmbiguous/ErrorN/A
Key Moments - 3 Insights
Why does the compiler assign the output lifetime to the input reference's lifetime when there is only one input reference?
Because Rule 1 states that if there is exactly one input lifetime, the output lifetime is assumed to be the same, simplifying annotations as shown in execution_table row 1.
What happens if a function has multiple input references but none is &self or &mut self?
Rule 3 applies, and the compiler cannot infer which input lifetime to assign to the output, causing an error unless lifetimes are explicitly annotated, as shown in execution_table row 3.
Why does the presence of &self or &mut self affect lifetime elision?
Rule 2 gives priority to &self or &mut self lifetimes for output references when multiple inputs exist, assuming the output borrows from self, as shown in execution_table row 2.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what output lifetime is assigned when the function has one input reference &str s?
ACompiler error
BSame as s
CSame as self
DNo lifetime needed
💡 Hint
Refer to execution_table row 1 where Rule 1 applies for one input reference
At which step does the compiler produce an error due to ambiguous lifetimes?
AStep 1
BStep 2
CStep 3
DStep 4
💡 Hint
Check execution_table row 3 where multiple inputs without self cause ambiguity
If a function has inputs &self and &str s, which lifetime does the output borrow from?
AFrom self
BFrom s
CCompiler error
DNo lifetime needed
💡 Hint
See execution_table row 2 where Rule 2 applies with &self present
Concept Snapshot
Lifetime Elision Rules in Rust:
1. One input reference: output borrows from it.
2. Multiple inputs with &self: output borrows from self.
3. Multiple inputs without &self: compiler error if ambiguous.
Simplifies lifetime annotations in function signatures.
Full Transcript
Lifetime elision rules in Rust help the compiler guess lifetimes in function signatures without explicit annotations. When a function has exactly one input reference, the output lifetime is assumed to be the same as that input (Rule 1). If there are multiple input references and one is &self or &mut self, the output lifetime is assumed to be the lifetime of self (Rule 2). If there are multiple input references but none is self, the compiler cannot decide which lifetime to assign to the output, resulting in an error unless lifetimes are explicitly annotated (Rule 3). These rules make writing safe code easier by reducing the need for verbose lifetime annotations.

Practice

(1/5)
1. Which of the following best describes the purpose of Rust's lifetime elision rules?
easy
A. To let Rust automatically fill in lifetimes in common cases without explicit annotations.
B. To force the programmer to always write explicit lifetime annotations.
C. To remove all lifetimes from the code for simplicity.
D. To allow Rust to ignore lifetime errors during compilation.

Solution

  1. Step 1: Understand lifetime elision rules

    Lifetime elision rules help Rust guess lifetimes automatically in common cases.
  2. 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.
  3. Final Answer:

    To let Rust automatically fill in lifetimes in common cases without explicit annotations. -> Option A
  4. Quick Check:

    Lifetime elision = automatic lifetime filling [OK]
Hint: Elision means Rust guesses lifetimes for you [OK]
Common Mistakes:
  • Thinking Rust always requires explicit lifetimes
  • Believing lifetimes are removed entirely
  • Assuming Rust ignores lifetime errors
2. Which of the following function signatures correctly uses lifetime elision rules in Rust?
easy
A. fn first_word<'a>(s: &'a str) -> &'a str
B. fn first_word(s: &str) -> &str
C. fn first_word(s: &str) -> &'a str
D. fn first_word<'a>(s: &str) -> &str

Solution

  1. 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.
  2. 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.
  3. Final Answer:

    fn first_word(s: &str) -> &str -> Option B
  4. Quick Check:

    One input ref means output ref gets same lifetime [OK]
Hint: One input ref means output ref lifetime is same [OK]
Common Mistakes:
  • Using undefined lifetime parameters
  • Mixing explicit and implicit lifetimes incorrectly
  • Forgetting elision rules allow omission
3. What will be the output of the following Rust code snippet?
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);
}
medium
A. Runtime error due to dangling reference
B. Longest string is: banana
C. Longest string is: apple
D. Compilation error due to missing lifetime annotations

Solution

  1. 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.
  2. Step 2: Confirm compilation behavior

    This results in a compilation error: `missing lifetime specifier`. The code does not compile.
  3. Final Answer:

    Compilation error due to missing lifetime annotations -> Option D
  4. Quick Check:

    Multiple input refs need explicit lifetimes [OK]
Hint: Two input refs to output requires explicit lifetimes [OK]
Common Mistakes:
  • Thinking elision allows compilation with multiple input refs
  • Believing it returns the longer string
  • Confusing runtime errors with lifetime errors
4. Identify the error in the following Rust function related to lifetime elision rules:
fn invalid_ref(x: &str, y: &str) -> &str {
    let result = String::from("hello");
    &result
}
medium
A. The function returns a reference to a local variable that will be dropped.
B. The function is missing lifetime annotations on parameters.
C. The function should return a String, not a reference.
D. The function should use explicit lifetime annotations to compile.

Solution

  1. Step 1: Analyze the returned reference

    The function returns a reference to 'result', a local String created inside the function.
  2. 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.
  3. Final Answer:

    The function returns a reference to a local variable that will be dropped. -> Option A
  4. Quick Check:

    Returning local reference causes dangling pointer [OK]
Hint: Never return reference to local variable [OK]
Common Mistakes:
  • Thinking missing lifetime annotations cause this error
  • Believing explicit lifetimes fix dangling references
  • Confusing return type with ownership
5. Given the following struct and method, which lifetime elision rule applies to the method's signature?
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?
hard
A. The return value has an unrelated anonymous lifetime.
B. The return value has the lifetime 'a from the struct definition.
C. The return value has the same lifetime as &self (the method receiver).
D. The return value has a static lifetime.

Solution

  1. 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.
  2. 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.
  3. Final Answer:

    The return value has the same lifetime as &self (the method receiver). -> Option C
  4. Quick Check:

    Method output lifetime = &self lifetime [OK]
Hint: Method output lifetime matches &self lifetime by elision [OK]
Common Mistakes:
  • Confusing struct lifetime with method output lifetime
  • Assuming static lifetime without reason
  • Ignoring elision rule for &self receiver
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard