---
title: "17.4 Elision rules"
description: "The three lifetime elision rules that let the compiler infer lifetimes on most function signatures, applied to functions you've already written without thinking about them."
url: "https://learnrust.net/chapter-17/elision-rules/"
last_updated: "2026-06-13"
---

# 17.4 Elision 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](https://learnrust.net/chapter-17/lifetime-annotations-in-functions/)). 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](https://learnrust.net/chapter-9/string-slices/) 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](https://learnrust.net/chapter-17/lifetime-annotations-in-functions/)) 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](https://learnrust.net/chapter-17/what-lifetimes-are/) 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.

<details class="solution">
<summary>Show solution</summary>

(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.

</details>

**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.

<details class="solution">
<summary>Show solution</summary>

`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).

</details>

**Question #3**

Does a method `fn name(&self) -> &str` need a lifetime annotation? Which rule decides?

<details class="solution">
<summary>Show solution</summary>

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.

</details>

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.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
