17.4Elision rules
You've written dozens of functions taking and returning references without a single 'a. The compiler accepted them because it filled in the lifetimes itself, following three fixed patterns called the elision rules ("elision" meaning "omission", the lifetimes are there, just left unwritten). This lesson spells out those three rules, applies them to functions you've already written, and explains why, in practice, you'll rarely write a lifetime annotation at all.
What elision is
Lifetime elision is a set of rules the compiler applies to fill in omitted lifetimes on function signatures. It's not inference in the open-ended sense; it's three specific patterns that cover the overwhelmingly common cases. If the rules determine every lifetime, you write nothing. If they leave any reference's lifetime undetermined, the compiler stops and asks you to annotate (the E0106 you saw with longest in lesson 17.2). So elision doesn't guess; it applies clear rules, and when they're not enough, it hands the job back to you.
First, two terms. An input lifetime is the lifetime on a parameter (&str arguments). An output lifetime is the lifetime on a return value (a returned &str). The rules are about deriving output lifetimes from input ones.
The three rules
Rule 1: each reference parameter gets its own lifetime. A function with one reference parameter gets one input lifetime, two parameters get two distinct ones, and so on. fn foo(x: &str, y: &str) is treated as fn foo<'a, 'b>(x: &'a str, y: &'b str). This rule just assigns the inputs; it never touches the output.
Rule 2: if there is exactly one input lifetime, it's assigned to all output lifetimes. A function with a single reference parameter that returns a reference: the output borrows from that one input, obviously, so the compiler links them. fn first_word(s: &str) -> &str becomes fn first_word<'a>(s: &'a str) -> &'a str automatically. This is why your first_word from lesson 9.7 never needed an annotation: one input, so the output's lifetime is unambiguous.
Rule 3: if one of the parameters is &self or &mut self, its lifetime is assigned to all output lifetimes. For methods, a returned reference is assumed to borrow from self (the most common case by far). So a method fn get_text(&self) -> &str needs no annotation; the output borrows from &self. This rule is why almost no methods carry lifetime annotations even when they return references.
After applying these three rules, if every output lifetime is determined, the signature compiles with no annotation. If any output lifetime is still unknown, elision fails and you must write the lifetimes yourself.
Why longest fails the rules
Now you can see precisely why longest (lesson 17.2) needed an annotation while first_word didn't. Walk longest(x: &str, y: &str) -> &str through the rules:
Rule 1 assigns each parameter its own lifetime: x: &'a str, y: &'b str. Rule 2 doesn't apply, there are two input lifetimes, not one, so the output can't be linked to "the one input." Rule 3 doesn't apply, there's no &self. After all three rules, the output -> &str still has no lifetime. Elision fails, and the compiler asks you to annotate, which is exactly the E0106 you saw. first_word, with one input, sails through on rule 2. The difference between the two functions is now mechanical, not mysterious: one input means elision works, two ambiguous inputs means it doesn't.
Key insight
The elision rules are why lifetimes feel rare: they cover the two most common shapes (one-reference-in-one-reference-out, and methods returning a borrow of self) completely, so you write nothing for those. You only reach for explicit 'a when a function has multiple reference inputs and returns one, leaving the compiler genuinely unable to tell which input the output borrows from. That's a real minority of functions, which is why most code is lifetime-annotation-free.
Why you'll rarely write 'a
Put the rules together and the practical upshot is clear: the vast majority of reference-taking functions either have one reference input (rule 2 handles them) or are methods borrowing self (rule 3 handles them). Both are extremely common; the multi-input-returning-a-reference case that defeats elision is comparatively rare. So in day-to-day Rust, you write reference-passing code freely and almost never annotate, and when you do hit the rare case, the compiler tells you exactly where with E0106. Lifetimes end up being something you handle in response to a specific, well-marked request, not a constant overhead, which is the reassurance lesson 17.1 opened with, now justified by the rules.
Best practice
Don't memorize the elision rules to apply them; memorize them to understand why the compiler sometimes does and sometimes doesn't ask for annotations. Write your reference-taking functions naturally, and when E0106 appears, recall that it means "elision couldn't determine an output lifetime", almost always because there are multiple reference inputs, and follow the compiler's suggested annotation. The rules explain the error; they're not a checklist you run by hand.
Quiz time
Question #1
State the three lifetime elision rules in your own words.
Show solution
(1) Each reference parameter gets its own input lifetime. (2) If there's exactly one input lifetime, it's given to all output lifetimes. (3) If a parameter is &self/&mut self, that lifetime is given to all output lifetimes. After applying them, if any output lifetime is still undetermined, the compiler requires an explicit annotation.
Question #2
Using the rules, explain why fn first_word(s: &str) -> &str compiles without annotation but fn longest(x: &str, y: &str) -> &str does not.
Show solution
first_word has one reference input, so rule 2 assigns that single input lifetime to the output: fully determined, no annotation needed. longest has two reference inputs, so rule 1 gives them separate lifetimes, rule 2 doesn't apply (not exactly one input), and rule 3 doesn't apply (no &self). The output lifetime stays undetermined, elision fails, and the compiler demands an annotation (E0106).
Question #3
Does a method fn name(&self) -> &str need a lifetime annotation? Which rule decides?
Show solution
No annotation needed. Rule 3 applies: because a parameter is &self, its lifetime is assigned to the output, so the returned &str is understood to borrow from self. This is why methods returning references almost never need explicit lifetimes.
There's one lifetime you've seen by name since chapter 5 but never examined: 'static, the lifetime of string literals. The last lesson of the chapter covers it, and warns about the tempting-but-wrong habit of slapping 'static on things to silence the borrow checker.