Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 18: Lifetimes, Relationships Not Durations

You will understand

  • Lifetimes as relationship contracts, not durations
  • The three elision rules and when to annotate
  • Why 'static does not mean "lives forever"

Reading time

45 min
+ 25 min exercises
Core Diagram

Lifetimes as Relationships Between Valid Regions

Valid borrow Rejected borrow Returned reference relationship time / program points → owner x lives here borrow r: &x 'a must stay inside x's valid region owner x borrow r wants to live longer ❌ reference outlives referent compiler rejects dangling relationship input x: &'a str input y: &'a str output: &'a str returned borrow cannot outlive the shortest valid input source
This is the lifetime reframe that matters: a lifetime annotation does not extend an object’s existence. It names the region within which a borrowed reference is allowed to be used.
Elision Rules

What the Compiler Infers for You

Rule 1 fn f(x: &str, y: &str) becomes &'a str, &'b str each input gets its own lifetime Rule 2 fn f(x: &str) -> &str becomes fn f<'a>(x: &'a str) -> &'a str single input lifetime flows to output Rule 3 fn get(&self) -> &str output ties to self's borrow
`'static`

Valid for the Whole Program

program start → program end string literal: &'static str local borrow stored in binary / static data segment

Chapter Resources

#![allow(unused)]
fn main() {
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

let result;
let s1 = String::from("long");
{
    let s2 = String::from("hi");
    result = longest(&s1, &s2);  // 'a = shorter of s1, s2
}                                // s2 dropped — result would dangle
// println!("{result}");         // E0597: s2 doesn't live long enough
}
'a annotation "The return value lives at most as long as both inputs." Not a duration — a relationship constraint.
Both inputs tied Compiler unifies 'a to the shorter of the two lifetimes.
E0597 s2 is dropped at }. result might hold a reference to s2, so compiler rejects.

In Your Language: Lifetimes vs Garbage Collection

Rust — explicit lifetime annotations
#![allow(unused)]
fn main() {
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}
// Compiler verifies both inputs outlive the return value
}
Go — GC handles it
func longest(x, y string) string {
    if len(x) > len(y) { return x }
    return y
}
// No annotation needed — GC keeps both alive
// But: unpredictable pause times, higher memory usage

Readiness Check - Lifetime Reasoning

Use this checkpoint to confirm you can reason about reference relationships, not just syntax.

SkillLevel 0Level 1Level 2Level 3
Explain what a lifetime meansI think it is a time durationI know it describes validity scopeI can explain it as a relationship between borrows and ownersI can teach why annotations do not extend object lifetime
Read lifetime signaturesI avoid annotated signaturesI can parse single-input/output signaturesI can explain multi-input relationships like longest<'a>I can redesign signatures to express clearer borrow contracts
Diagnose lifetime errorsI guess and add annotations randomlyI can recognize outlives problemsI can pinpoint the dropped owner causing E0597/E0515I can choose when returning owned values is the better design

If any row is below Level 2, revisit Chapter 11 and run Drill Deck 2 again.

Compiler Error Decoder - Lifetime Relationships

Error codeWhat it usually meansTypical fix direction
E0597Referenced value does not live long enoughMove owner to a wider scope or return owned data instead
E0515Returning a reference to local dataReturn an owned value, or borrow from caller-provided inputs
E0621Function signature lifetime contract mismatches implementationAlign annotations with real input-output borrow relationship

Treat lifetime errors as relationship mismatches, not annotation shortages.

Step 1 - The Problem

Learning Objective By the end of this chapter, you should be able to explain how lifetimes define relationships between borrowed data, rather than magically extending how long data exists.