Rust by Example: Lifetime Annotations
Dive deeper into explicit lifetime annotations. Learn syntax for annotating structs and function signatures to help the compiler understand relationships between the lifetimes of different references.
Code
// Struct with a reference
// We must specify that 'ImportantExcerpt' cannot outlive the string it holds
struct ImportantExcerpt<'a> {
part: &'a str,
}
impl<'a> ImportantExcerpt<'a> {
// Method with lifetime elision (compiler infers this)
fn level(&self) -> i32 {
3
}
// Method where return value lifetime is tied to &self
fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("Attention please: {}", announcement);
self.part
}
}
fn main() {
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence = novel.split('.').next().expect("Could not find a '.'");
// 'i' holds a reference to a slice of 'novel'
let i = ImportantExcerpt {
part: first_sentence,
};
println!("Excerpt: {}", i.part);
// Static lifetime: lives for the entire program duration
let s: &'static str = "I have a static lifetime.";
println!("{}", s);
}Explanation
Lifetime annotations are also required for structs that hold references. This ensures that the struct itself cannot outlive the data it points to. We enforce this by adding a lifetime parameter ('a) to the struct definition. If the referenced data is dropped, the struct instance becomes invalid, preventing use-after-free bugs.
Rust simplifies common patterns with Lifetime Elision Rules. For example, if a method takes &self, the compiler assumes that any returned reference likely comes from self, so it assigns the lifetime of self to the return value automatically. This keeps the code clean while maintaining safety.
The 'static lifetime is special. It denotes a reference that can live for the entire duration of the program. All string literals have the 'static lifetime because they are baked directly into the program's binary.
Code Breakdown
struct ImportantExcerpt<'a>. This declaration says that an instance of ImportantExcerpt cannot outlive the reference it holds in part. If the string pointed to by part is dropped, the struct instance becomes invalid.fn announce_and_return_part. Even though there are two input references (&self and announcement), Rust's elision rules infer that the return value lifetime is tied to &self, not announcement.&'static str. This is the only lifetime name that is reserved. It means the data is guaranteed to be available for the remaining lifetime of the running program.
