A lifetime is the period when a value is valid: after its memory is allocated and before the value is dropped. A local value might last for one function call; a global value might last for the program’s entire run. Rust checks these boundaries before the program runs, so an attempt to use a value outside its lifetime fails to compile rather than becoming an invalid memory access. section 2.3 section 2.6
Start with ownership. A local value is dropped when it goes out of scope. Passing an owned artwork to a function moves ownership into that function: the caller’s variable can no longer be used, even though the artwork remains valid under its new owner. A lifetime graph makes the change visible by marking when each variable can be used. section 2.3 section 2.2
A borrowed result must remain valid
Given `let numbers = vec![1, 2, 3, 4, 5];`, a helper can return its first element with `fn get_value(numbers: &Vec<i32>) -> &i32 { &numbers[0] }`. The compiler can infer that the returned reference is tied to the input reference. By contrast, `fn get_value() -> &i32 { let x = 4; &x }` cannot return a reference to its local `x`. If a caller still intends to use the borrowed element, it also cannot call `numbers.push(6)` first: that would mutate the vector while its immutable borrow is in use. section 4.4.1
$ cargo run
error[E0502]: cannot borrow `numbers` as mutable
because it is also borrowed as immutable
--> src/main.rs:6:3
|
4 | let value = get_value(&numbers);
| -------- immutable borrow occurs here
5 |
6 | numbers.push(6);
| ^^^^^^^^^^^^^^^ mutable borrow occurs here
7 |
8 | println!("value: {}", value);
| ----- immutable borrow later used here
The compiler diagnostic identifies the immutable borrow, the attempted mutable borrow, and the later use that keeps the first borrow relevant. section 4.4.1
Sometimes the compiler needs the relationship between references stated explicitly. Adding an unrelated `s: &str` argument to `get_value` leaves a signature with two input references and one output reference; the compiler cannot tell which input the output borrows from. A named lifetime resolves that question: `fn get_value<'a>(numbers: &'a Vec<i32>, s: &str) -> &'a i32` ties the result to `numbers`, not to `s`. The annotation describes the relationship; it does not make the borrowed value live longer. section 4.4.1
Listing 4.13 Returning a reference to an argument
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
let value = get_value(&numbers, "Getting the number");
println!("value: {}", value);
}
fn get_value<'a>(numbers: &'a Vec<i32>, s: &str) -> &'a i32 { #1
println!("{}", s);
&numbers[0]
}
The annotated helper shows the small signature change needed when an additional reference makes lifetime inference insufficient. section 4.4.1
The `&'static str` type offers another concrete case: its annotation says the reference remains valid for the program’s entire runtime, as a string literal can. Lifetime checks also support sharing memory across foreign-function boundaries by making the responsibility for valid references and resource cleanup clearer. section 2.4 section 1.3







