The three rules Rust uses to infer lifetimes automatically, so you understand when you need to annotate and when the compiler handles it for you.
Rust has explicit lifetime syntax ('a, 'b) but you don't write it most of the time. The compiler applies three elision rules in order and only forces you to annotate when it can't figure it out.
Rule 1: Each parameter that is a reference gets its own lifetime.
fn foo(x: &str, y: &str)
// becomes:
fn foo<'a, 'b>(x: &'a str, y: &'b str)Rule 2: If there's exactly one input lifetime, it's assigned to all output lifetimes.
fn first_word(s: &str) -> &str
// becomes:
fn first_word<'a>(s: &'a str) -> &'a strThis is why first_word compiles without annotations — rule 2 handles it.
Rule 3: If there's a &self or &mut self parameter, its lifetime is assigned to all output lifetimes.
Karanveer Singh Shaktawat
Full Stack Engineer & Infrastructure Architect
Building portfolio, contributing to open source, and seeking remote full-time roles with significant technical ownership.
Pick what you want to hear about — I'll only email when it's worth it.
Did this resonate?
The difference between static dispatch (impl Trait) and dynamic dispatch (dyn Trait) — not just syntax, but a real tradeoff.
How to use Docker multi-stage builds to go from a 2GB Rust build image to a 12MB production image.
impl Config {
fn description(&self) -> &str {
&self.desc
}
}
// The returned &str has the same lifetime as &self — compiler knows this.If none of the three rules produce an unambiguous result, you annotate.
// Two input references, no &self — rule 2 doesn't apply, ambiguous output
fn longer<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}The annotation 'a here says: the returned reference lives at least as long as the shorter of x and y. The compiler can't infer this from the rules alone.
If you're writing a function that returns a reference and the compiler complains, ask: does the returned reference come from self, from one specific input, or is it ambiguous? If ambiguous, annotate. The annotation isn't for the compiler's benefit — it's a contract you're making explicit.