Lifetimes help Rust keep track of how long references are valid. This stops bugs where a program tries to use data that no longer exists.
Why lifetimes exist in Rust
fn example<'a>(input: &'a str) -> &'a str { input }
The 'a is a lifetime parameter that tells Rust how long the reference lives.
Lifetimes are written with an apostrophe followed by a name, like 'a.
'a ensures the returned reference is valid as long as the input is.fn first_word<'a>(s: &'a str) -> &'a str { &s[..1] }
fn no_lifetime(x: &str) -> &str {
x
}struct Important<'a> {
data: &'a str,
}This program finds the longest of two string slices. The lifetime 'a ensures the returned reference is valid as long as both inputs are.
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } } fn main() { let string1 = String::from("apple"); let string2 = "banana"; let result = longest(string1.as_str(), string2); println!("The longest string is: {}", result); }
Lifetimes do not change how long data lives; they tell the compiler to check references for safety.
Rust's lifetime errors help catch bugs before the program runs.
Understanding lifetimes helps you write safe and efficient Rust code.
Lifetimes keep track of how long references are valid.
They prevent bugs from using data that no longer exists.
Rust uses lifetimes to ensure memory safety without a garbage collector.
Practice
Why does Rust use lifetimes like 'a in its code?
Solution
Step 1: Understand what lifetimes represent
Lifetimes in Rust show how long a reference is valid to prevent dangling references.Step 2: Connect lifetimes to safety
They ensure references do not outlive the data they point to, avoiding bugs.Final Answer:
To ensure references do not outlive the data they point to -> Option DQuick Check:
Lifetimes = prevent dangling references [OK]
- Thinking lifetimes speed up code
- Confusing lifetimes with garbage collection
- Believing lifetimes allow multiple mutable references
Which of the following is the correct way to declare a function with a lifetime parameter 'a for a reference argument in Rust?
fn example(____ s: &'a str) -> &'a str { s }Solution
Step 1: Recall lifetime syntax in function signatures
Lifetimes are declared before the function name with'aand used on references.Step 2: Match correct syntax
fn example<'a>(s: &'a str) -> &'a str correctly declares'aand uses it on both input and output references.Final Answer:
fn example<'a>(s: &'a str) -> &'a str -> Option AQuick Check:
Lifetime syntax = fn example<'a>(s: &'a str) -> &'a str [OK]
- Putting lifetime after & instead of before type
- Forgetting to declare lifetime before function name
- Using lifetime on non-reference types
What will this Rust code print?
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
fn main() {
let s1 = String::from("apple");
let s2 = "banana";
let result = longest(&s1, s2);
println!("{}", result);
}Solution
Step 1: Understand function longest behavior
It returns the longer string slice between x and y.Step 2: Compare lengths of "apple" and "banana"
"apple" has 5 letters, "banana" has 6, so it returns "banana".Final Answer:
banana -> Option BQuick Check:
Longest string = banana [OK]
- Assuming s1 is longer without counting
- Thinking lifetimes cause compile error here
- Confusing references with ownership causing runtime error
Identify the error in this Rust code related to lifetimes:
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s
}
fn main() {
let word;
{
let s = String::from("hello world");
word = first_word(&s);
}
println!("{}", word);
}Solution
Step 1: Analyze lifetime of variable s
Variable s is created inside inner block and dropped after it ends.Step 2: Check lifetime of returned reference word
word holds reference to s, but s is dropped before println!, causing dangling reference.Final Answer:
Error: returned reference may outlive borrowed data -> Option CQuick Check:
Dangling reference error = Error: returned reference may outlive borrowed data [OK]
- Ignoring scope of s and thinking code is safe
- Assuming missing lifetime annotation causes error here
- Confusing mutable borrow errors with lifetime errors
You want to write a function that returns a reference to the longer string slice between two inputs, but one input is owned String and the other is a string slice &str. How should you use lifetimes to make this safe and correct?
Solution
Step 1: Understand input types and lifetimes
Owned String must be converted to a string slice (&str) to use lifetimes uniformly.Step 2: Use one lifetime parameter for both inputs and output
This ensures the returned reference is valid as long as both inputs are valid.Final Answer:
Convert the owned String to a slice and use a single lifetime for both inputs and output -> Option AQuick Check:
Single lifetime with slices = Convert the owned String to a slice and use a single lifetime for both inputs and output [OK]
- Returning owned String without references when references expected
- Using multiple lifetimes causing borrow conflicts
- Forgetting to convert String to &str before comparison
Ready to prove it?
Pass the test and this pattern moves unknown
