Appendix A: The Story of Colored Stickers (Lifetimes)
Age Rating: 🚀 (Ages 15+)
📑 Table of Contents
- A.1. The Yogurt Expiration Date Story
- A.2. Rule #1: Every Reference Has an Expiration Date
- A.3. Helping the Compiler with
'a - A.4. Lifetime Elision (When the Compiler Guesses for You)
- A.5. Lifetimes in Structs
- A.6. Exercises
- A.7. Summary
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:
-
Rule 1: Every reference parameter gets its own hidden lifetime.
(e.g.,fn foo(x: &str)→fn foo<'a>(x: &'a str)) -
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 ass) -
Rule 3: If there are multiple input references and one of them is
&selfor&mut self(i.e., methods), the output gets the lifetime ofself.
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