Lifetimes: The Solution to Dangling References
What we can see here is that dangling references are caused by functions losing information about where references come from.
The compiler can only decide if the function is correct if it knows how the lifetimes of its inputs and outputs interact. So, we need to tell the compiler when lifetimes of inputs and outputs will be the same.
What we can do is tell the computer "my function works for any lifetimes, as long as the lifetimes of these inputs/outputs are the same". Let's take a look at the syntax of this:
fn some_if_greater<'lifetime1, 'lifetime2>(number: &'lifetime1 i32, greater_than: &'lifetime2 i32) -> Option<&'lifetime1 i32> { if number > greater_than { Some(number) } else { None } } fn main() { let (n, gt) = (7, 4); let test = some_if_greater(&n, >); }
Let's walk through what this does:
fn my_function<'lifetime1, 'lifetime2>(...)
: what we're doing here is choosing some names for the lifetimes our program requires.number: &'lifetime1 i32
: this is us telling the compiler that this reference must live for some region of code called'lifetime1
.greater_than: &'lifetime2 i32
: this is us telling the compiler that this reference must live for some region of code called'lifetime2
. This means that the lifetimes ofgreater_than
andnumber
don't have to relate at all.-> Option<&'lifetime1 i32>
: this is where lifetimes are important. what we're saying is thatnumber
and our return value must be valid for exactly the same region of code.
So, what we've done is told the compiler that our function can only be called
if number
and the return are valid in the same region of code.
Exercise: Annotate lifetimes
Just to get some initial practice, the exercise in this section is to annotate lifetimes on some of the examples of the last two chapters.
You will need to:
- decide how many lifetime parameters are necessary
- name each of those lifetime parameters, and put them inside
<
angle brackets>
after the function's name. - annotate every reference with the appropriate lifetime
- check the code compiles
- think about what region of code each lifetime could be
You will notice each function has the #[lifetimes_required(!)]
annotation. You will need
to leave it there to complete this exercise. This instructs the compiler to throw an
error whenever you miss a lifetime; even if the compiler doesn't need the lifetime.