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

Appendix A: The Story of Colored Stickers (Lifetimes)

Age Rating: 🚀 (Ages 15+)


📑 Table of Contents


A.1. The Yogurt Expiration Date Story

Ferris buys a local space yogurt. On the cup it says: “Expiration date: April 20, 2026.” Until that date, he can eat it safely. After that, the yogurt goes bad and will give him a stomach ache. 🤢

In Rust, every reference also has an “expiration date”. We call this a lifetime. It tells the compiler how long the reference remains valid.

👨‍👩‍👧 Note for parents and educators
Lifetimes are one of Rust’s most unique – and sometimes confusing – concepts. This appendix deepens the brief introduction from Chapter 10. The goal is not mastery, but familiarity. If your child doesn’t understand everything the first time, that’s perfectly fine – most adult programmers also need practice. The official Rust book has an entire chapter on lifetimes:
doc.rust-lang.org/book/ch10-03-lifetime-syntax.html


A.2. Rule #1: Every Reference Has an Expiration Date

The Rust compiler always checks that no reference outlives the data it points to.

#![allow(unused)]
fn main() {
let r;                // r is an empty reference (doesn't point to anything yet)
{
    let x = 5;        // x is created
    r = &x;           // r borrows x
}                     // x dies here (the yogurt has expired!)
println!("{}", r);    // ❌ Error! r points to expired data
}

The compiler calmly says: “No friend, r lives longer than x. That’s dangerous. I won’t allow it.”

🛡️ This is one of the reasons Rust is one of the safest programming languages.


A.3. Helping the Compiler with 'a

Sometimes the compiler cannot guess which input the output of a function belongs to. For example, a function that returns the longer of two strings:

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

The compiler gets confused: “I don’t know if the output refers to x or y. So I can’t determine its expiration date.”

We help it with a lifetime label 'a (apostrophe + a letter):

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

Meaning: “Dear compiler, x and y are valid at least as long as 'a. The output will also be valid for 'a. Whichever input lives shorter, the output will live exactly that long.”

🔹 'a is just a name. You could also write 'fruit or 'crab. The only rule is that it starts with an apostrophe.


A.4. Lifetime Elision (When the Compiler Guesses for You)

Good news: In 95% of cases, you don’t need to write 'a at all! The compiler has three simple rules:

  1. Rule 1: Every reference parameter gets its own hidden lifetime.
    (e.g., fn foo(x: &str)fn foo<'a>(x: &'a str))

  2. Rule 2: If there’s exactly one input reference parameter, the output gets that same lifetime.
    (e.g., fn first_word(s: &str) -> &str → the output lives exactly as long as s)

  3. Rule 3: If there are multiple input references and one of them is &self or &mut self (i.e., methods), the output gets the lifetime of self.

Thanks to these rules, you wrote many programs in this book without ever typing a single 'a. Rust handled everything behind the scenes. 🧠


A.5. Lifetimes in Structs

If a struct wants to hold a reference, we must write the lifetime explicitly:

#![allow(unused)]
fn main() {
struct Excerpt<'a> {
    part: &'a str,
}
}

This means: “This struct holds a &str that is valid at least for 'a. You can never create an Excerpt that outlives the original string.”

fn main() {
    let novel = String::from("Once upon a time...");
    let first_sentence = novel.split('.').next().unwrap();
    let excerpt = Excerpt { part: first_sentence };
    println!("{}", excerpt.part);
} // novel dies here, and excerpt dies with it – correct.

If you try to cheat, the compiler yells:

#![allow(unused)]
fn main() {
let excerpt;
{
    let novel = String::from("Short story");
    excerpt = Excerpt { part: &novel };
} // novel dies here
println!("{}", excerpt.part); // ❌ Error! excerpt points to dead data
}

A.6. Exercises

Exercise 1: Find the Lifetime Problem

Why does the following code fail? Can you fix it by adding 'a?

#![allow(unused)]
fn main() {
fn dangerous() -> &i32 {
    let x = 42;
    &x
}
}

Answer: x is created inside the function and dies when the function returns. You cannot return a reference to it. No lifetime annotation can fix this because the data doesn’t exist outside the function. Solution: return the value itself (return x), not a reference.


Exercise 2: Fix the Function with Lifetimes

Rewrite the following function so that it has a correct lifetime annotation and compiles:

#![allow(unused)]
fn main() {
fn first_or_second(a: &str, b: &str, choice: bool) -> &str {
    if choice { a } else { b }
}
}

Answer:

#![allow(unused)]
fn main() {
fn first_or_second<'a>(a: &'a str, b: &'a str, choice: bool) -> &'a str {
    if choice { a } else { b }
}
}

Exercise 3: Struct with Lifetime

Create a struct named BookReference with one field page: &str. Add the correct lifetime annotation. Then in main, create a String and a BookReference that points to it.

Answer:

struct BookReference<'a> {
    page: &'a str,
}

fn main() {
    let text = String::from("Page 42");
    let ref_page = BookReference { page: &text };
    println!("{}", ref_page.page);
}

A.7. Summary

  • ✅ Every reference has a lifetime (expiration date).
  • ✅ The compiler automatically prevents references from outliving their data.
  • ✅ Sometimes we help the compiler with 'a.
  • ✅ Three elision rules make most lifetimes invisible.
  • ✅ Structs that hold references must declare a lifetime.

🧠 Sometimes it’s hard, and that’s okay! Lifetimes can be confusing – even for experienced programmers. If you don’t grasp everything today, don’t worry. With practice, they will become natural. Rust is always there to protect you from memory mistakes. 🛡️


🖼️ Illustration Prompt (for artist or AI):
A cute cartoon yogurt cup with a glowing expiration date sticker labeled "lifetime 'a". A friendly compiler robot holding a magnifying glass checks the sticker and gives a green checkmark. Ferris the crab points at the cup, explaining. Background: a simple kitchen shelf with other dairy products. Style: warm, educational children's book, soft lighting, 16:9