Lifetimes
Lifetimes help the compiler understand how long references are valid.
Lifetimes
Lifetimes are generic parameters that tell the compiler how long references are valid.
Why Do We Need Lifetimes?
RUSTfn longest(x: &str, y: &str) -> &str { // ERROR! if x.len() > y.len() { x } else { y } }
The compiler doesn't know which parameter the return reference points to, so it can't guarantee validity.
Lifetime Annotations
RUSTfn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
The 'a is a lifetime parameter indicating that both parameters and the return value have the same lifetime.
Lifetime Elision
In some cases, the compiler can automatically infer lifetimes:
RUSTfn first_word(s: &str) -> &str { // Automatic lifetime // ... }
In Structs
RUSTstruct ImportantExcerpt<'a> { part: &'a str, }
Code Examples
Basic Lifetime
Using lifetime annotations
fn main() {
let string1 = String::from("long string is long");
{
let string2 = String::from("xyz");
let result = longest(string1.as_str(), string2.as_str());
println!("The longer string: {}", result);
}
}
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}Explanation:
The lifetime annotation `'a` indicates that the return reference is valid for at least as long as the shorter-lived parameter.
Struct Lifetime
Using lifetimes in structs
struct ImportantExcerpt<'a> {
part: &'a str,
}
fn main() {
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence = novel.split('.').next().expect("Could not find a '.'");
let i = ImportantExcerpt {
part: first_sentence,
};
println!("{}", i.part);
}Explanation:
When a struct contains a reference field, lifetime annotations must be used. This guarantees that the reference is valid for at least as long as the struct instance.
Exercises
Lifetime Annotation
Fix this function with lifetime annotations!
Starter Code:
fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() {
x
} else {
y
}
}