Skip to content
DocsRust LearningadvancedLifetimes
Chapter 11 of 19·advanced·8 min read

Lifetimes

Thời Gian Sống

Lifetime annotations and elision rules

Hover or tap any paragraph to see Vietnamese translation

What Are Lifetimes and Why They Exist

Lifetimes are Rust's mechanism for ensuring that references are always valid — they never point to memory that has been freed (a dangling reference). The borrow checker tracks how long each value lives and how long each reference lives to guarantee that no reference outlives the data it points to.

dangling_ref.rs
1fn main() {2    // This is what lifetimes prevent:3    let r;4    {5        let x = 5;6        r = &x;7        // x goes out of scope here and is dropped8    }9    // println!("{r}"); // ERROR: x does not live long enough10    // r would be a dangling reference to freed stack memory1112    // This is fine: r lives shorter than x13    let x = 5;14    let r = &x;15    println!("{r}"); // 5 — x is still alive16}

In most cases Rust infers lifetimes automatically through elision rules. You only need to write lifetime annotations when the compiler cannot determine the relationship between lifetimes.

Lifetime Annotation Syntax ('a)

Lifetime annotations do not change how long a reference lives — they describe the relationship between the lifetimes of multiple references. They start with a tick and are typically short lowercase letters like 'a or 'b.

lifetime_syntax.rs
1// &i32         — a reference (compiler infers lifetime)2// &'a i32      — a reference with an explicit lifetime 'a3// &'a mut i32  — a mutable reference with lifetime 'a45// This function needs a lifetime annotation because it6// returns a reference and the compiler cannot tell whether7// it comes from x or from y8fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {9    if x.len() > y.len() { x } else { y }10}1112fn main() {
Info
'a in longest does not mean both parameters must live the same length — it means the returned reference will be valid for no longer than the shorter-lived of the two inputs.

Lifetimes in Function Signatures

You need lifetime annotations in function signatures when a function takes multiple references and returns a reference — the compiler needs to know which input the returned reference relates to.

fn_lifetimes.rs
1// Returns reference to x — lifetime tied to x only2fn first_word<'a>(s: &'a str) -> &'a str {3    let bytes = s.as_bytes();4    for (i, &byte) in bytes.iter().enumerate() {5        if byte == b' ' {6            return &s[0..i];7        }8    }9    s10}1112// When returning a reference only tied to one parameter,

Lifetime Elision Rules (3 Rules)

The Rust compiler has three elision rules that let you omit lifetime annotations in common situations. If after applying the rules there are still references without a lifetime, the compiler reports an error.

Rule 1 — Each Parameter Gets Its Own Lifetime

elision_rule1.rs
1// You write:2fn foo(x: &str, y: &str) -> &str { x }34// Compiler expands to:5fn foo<'a, 'b>(x: &'a str, y: &'b str) -> &str { x }6// Return still has no lifetime — rules 2 and 3 apply next

Rule 2 — One Input Parameter Gives Its Lifetime to Output

elision_rule2.rs
1// You write:2fn first(s: &str) -> &str { s }34// Compiler expands to (rule 1 then rule 2):5fn first<'a>(s: &'a str) -> &'a str { s }6// Works! Only one input reference, so its lifetime propagates to output

Rule 3 — Method with &self: self Gives Its Lifetime to Output

elision_rule3.rs
1struct Important<'a> {2    part: &'a str,3}45impl<'a> Important<'a> {6    // You write:7    fn announce(&self, msg: &str) -> &str {8        self.part9    }10    // Compiler expands (rule 1, then rule 3 — &self wins):11    // fn announce<'b>(&'a self, msg: &'b str) -> &'a str { self.part }12}1314fn main() {15    let novel = String::from("Call me Ishmael. Some years ago...");16    let first_sentence = novel.split('.').next().unwrap();17    let imp = Important { part: first_sentence };18    println!("{}", imp.announce("Attention!"));19}
Tip
Most everyday Rust functions and methods use lifetime elision. You only need explicit annotations when the compiler reports ambiguity.

Lifetimes in Struct Definitions

If a struct holds a reference you must declare a lifetime annotation on the struct. This ensures the struct cannot outlive the data it references.

struct_lifetimes.rs
1// Struct that holds a reference — needs lifetime annotation2#[derive(Debug)]3struct Excerpt<'a> {4    text: &'a str,5}67impl<'a> Excerpt<'a> {8    fn level(&self) -> i32 { 3 }910    fn announce_and_return(&self, msg: &str) -> &str {11        println!("Attention: {msg}");12        self.text // lifetime elision rule 3 applies here

The Static Lifetime ('static)

The 'static lifetime is the longest possible lifetime. A 'static reference lives for the entire runtime of the program. String literals are 'static because they are stored in the program binary.

static_lifetime.rs
1// String literals have 'static lifetime2let s: &'static str = "I live forever";34// Static variables also have 'static lifetime5static GREETING: &str = "Hello";67// 'static bound means: the type contains no non-static references8// (does NOT mean it lives forever — just that it COULD)9fn takes_static<T: 'static>(val: T) {10    println!("Got a static-safe value");11}12

Lifetime Bounds on Generics

You can combine lifetimes and generic trait bounds. The bound T: 'a means the type T must live at least as long as the lifetime 'a.

lifetime_bounds.rs
1use std::fmt::Display;23// T must implement Display AND must live at least as long as 'a4fn longest_with_announcement<'a, T>(5    x: &'a str,6    y: &'a str,7    ann: T,8) -> &'a str9where10    T: Display,11{12    println!("Announcement: {ann}");

Common Lifetime Patterns and Pitfalls

Dangling References

no_dangle.rs
1// This does NOT compile — classic dangling reference2// fn dangle() -> &String {3//     let s = String::from("hello");4//     &s  // s is dropped at end of function — reference invalid!5// }67// Fix: return the owned value8fn no_dangle() -> String {9    let s = String::from("hello");10    s // ownership moves out, no dangling11}1213fn main() {14    let s = no_dangle();15    println!("{s}");16}

Struct Outliving Its References

struct_lifetime_pitfall.rs
1struct Config<'a> {2    host: &'a str,3    port: u16,4}56fn main() {7    let config;8    {9        let host = String::from("localhost");10        config = Config { host: &host, port: 8080 };11        println!("{}:{}", config.host, config.port); // fine here12        // host dropped at end of this block13    }14    // println!("{}", config.host); // ERROR: host dropped, config dangling15}
  • Add lifetime annotations when the compiler asks — do not guess ahead
  • Prefer owned types (String, Vec) in structs to avoid lifetime complexity
  • Use 'static sparingly — often 'static is not what you actually need
  • The borrow checker is your ally — it prevents you from writing code with undefined behavior
Tip
If you find yourself fighting lifetimes, consider refactoring to use owned data instead of references. This is often the correct solution.

Key Takeaways

Điểm Chính

  • Lifetimes ensure references remain valid for their entire useLifetime đảm bảo tham chiếu hợp lệ trong suốt thời gian sử dụng
  • Lifetime elision rules handle most cases automaticallyQuy tắc bỏ qua lifetime xử lý tự động hầu hết trường hợp
  • Structs holding references must declare lifetime parametersStruct chứa tham chiếu phải khai báo tham số lifetime
  • 'static lifetime means the reference lives for the entire programLifetime 'static nghĩa là tham chiếu tồn tại suốt chương trình

Practice

Test your understanding of this chapter

Quiz

Why does the longest function require a lifetime annotation on its return type?

Tại sao hàm longest yêu cầu annotation lifetime trên kiểu trả về?

Quiz

Which lifetime elision rule covers a method that takes &self and returns a reference?

Quy tắc bỏ qua lifetime nào áp dụng cho phương thức nhận &self và trả về một tham chiếu?

True or False

Lifetime annotations change how long a reference is valid by extending the lifetime of the underlying data.

Annotation lifetime thay đổi bao lâu một tham chiếu hợp lệ bằng cách kéo dài lifetime của dữ liệu bên dưới.

True or False

A struct that holds a reference field must declare a lifetime parameter so the compiler can guarantee the struct does not outlive the data it references.

Một struct chứa trường tham chiếu phải khai báo tham số lifetime để trình biên dịch đảm bảo struct không tồn tại lâu hơn dữ liệu mà nó tham chiếu.

Code Challenge

Declare a lifetime parameter on a struct

Khai báo tham số lifetime trên một struct

#[derive(Debug)]
struct Excerpt<> {
    text: &'a str,
}

Chapter Complete!

Great job! Keep the momentum going.

Your progress0 of 19 chapters read
← → to navigate chapters
Built: 4/8/2026, 12:01:11 PM