Rust continuation
Series 3: Advanced Rust
This continues the intermediate Rust tutorial with lifetimes, smart pointers, async internals, macros, testing, and practical next steps for real backend work.
โณ What Are Lifetimes?
Teaching the compiler how long references live
You already know that Rust's ownership system prevents dangling references. But sometimes the compiler needs YOUR help to figure out how long a reference is valid โ especially when multiple references are involved.
A lifetime is a label that describes how long a reference is valid. Lifetimes don't change how long things live โ they just *describe* it so the compiler can verify safety.
The good news: Rust infers lifetimes automatically in most cases. You only need to write them explicitly when the compiler can't figure it out on its own.
โณ The Analogy: Library Books
Imagine you borrow a book from a library. The library has rules: you can't keep reading a book after you've returned it. The librarian (Rust's compiler) tracks when each book was borrowed and when it must be returned.
Now imagine you photocopy a page from the book. That photocopy is only valid while you still have the book. If you return the book but keep the photocopy and try to use it โ that's a dangling reference! Lifetimes are how the compiler tracks these "how long is this reference valid?" relationships.
The Dangling Reference Problem
This is the bug lifetimes prevent. The compiler catches this at compile time โ no runtime crash.
fn main() {
let reference;
{
let value = 5;
reference = &value; // Borrow 'value'
} // 'value' is dropped here โ it's gone!
// ERROR: 'value' does not live long enough
// println!("{}", reference); // Would be a dangling reference!
}
// The compiler's error message is very clear:
// "borrowed value does not live long enough"
// This is exactly the kind of bug C/C++ programs crash from.
// Rust catches it before your program even runs.When Lifetimes Are Inferred (Most of the Time)
Rust has 'lifetime elision rules' โ patterns so common that the compiler handles them automatically. You don't write lifetimes here, but they exist implicitly.
// Rust infers the lifetime here โ no annotation needed
// The returned reference lives as long as the input reference
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &byte) in bytes.iter().enumerate() {
if byte == b' ' {
return &s[0..i];
}
}
&s[..]
}
fn main() {
let sentence = String::from("hello world");
let word = first_word(&sentence);
// 'word' borrows from 'sentence', so both must be alive together
println!("First word: {}", word);
// sentence.clear(); // ERROR: can't mutate while word borrows it
}1 / 11
