2023-11-29 10:39:24 -05:00
|
|
|
---
|
|
|
|
minutes: 10
|
|
|
|
---
|
|
|
|
|
2023-12-13 07:51:34 -05:00
|
|
|
# Lifetime Annotations
|
2023-11-29 10:39:24 -05:00
|
|
|
|
2023-12-13 07:51:34 -05:00
|
|
|
A reference has a _lifetime_, which must not "outlive" the value it refers to.
|
|
|
|
This is verified by the borrow checker.
|
2023-11-29 10:39:24 -05:00
|
|
|
|
2023-12-31 00:15:07 +01:00
|
|
|
The lifetime can be implicit - this is what we have seen so far. Lifetimes can
|
|
|
|
also be explicit: `&'a Point`, `&'document str`. Lifetimes start with `'` and
|
|
|
|
`'a` is a typical default name. Read `&'a Point` as "a borrowed `Point` which is
|
|
|
|
valid for at least the lifetime `a`".
|
2023-11-29 10:39:24 -05:00
|
|
|
|
|
|
|
Lifetimes are always inferred by the compiler: you cannot assign a lifetime
|
|
|
|
yourself. Explicit lifetime annotations create constraints where there is
|
|
|
|
ambiguity; the compiler verifies that there is a valid solution.
|
|
|
|
|
|
|
|
Lifetimes become more complicated when considering passing values to and
|
|
|
|
returning values from functions.
|
|
|
|
|
2023-12-31 00:15:07 +01:00
|
|
|
<!-- The multi-line formatting by rustfmt in left_most is apparently
|
|
|
|
intentional: https://github.com/rust-lang/rustfmt/issues/1908 -->
|
|
|
|
|
2023-12-13 19:41:32 +01:00
|
|
|
```rust,editable,compile_fail
|
2023-11-29 10:39:24 -05:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct Point(i32, i32);
|
|
|
|
|
|
|
|
fn left_most(p1: &Point, p2: &Point) -> &Point {
|
2023-12-31 00:15:07 +01:00
|
|
|
if p1.0 < p2.0 {
|
|
|
|
p1
|
|
|
|
} else {
|
|
|
|
p2
|
|
|
|
}
|
2023-11-29 10:39:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
2023-12-31 00:15:07 +01:00
|
|
|
let p1: Point = Point(10, 10);
|
|
|
|
let p2: Point = Point(20, 20);
|
|
|
|
let p3 = left_most(&p1, &p2); // What is the lifetime of p3?
|
|
|
|
println!("p3: {p3:?}");
|
2023-11-29 10:39:24 -05:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
<details>
|
|
|
|
|
2024-03-06 05:28:55 +08:00
|
|
|
In this example, the compiler does not know what lifetime to infer for `p3`.
|
2023-12-31 00:15:07 +01:00
|
|
|
Looking inside the function body shows that it can only safely assume that
|
|
|
|
`p3`'s lifetime is the shorter of `p1` and `p2`. But just like types, Rust
|
2023-11-29 10:39:24 -05:00
|
|
|
requires explicit annotations of lifetimes on function arguments and return
|
|
|
|
values.
|
|
|
|
|
|
|
|
Add `'a` appropriately to `left_most`:
|
|
|
|
|
|
|
|
```rust,ignore
|
|
|
|
fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {
|
|
|
|
```
|
|
|
|
|
2023-12-31 00:15:07 +01:00
|
|
|
This says, "given p1 and p2 which both outlive `'a`, the return value lives for
|
|
|
|
at least `'a`.
|
2023-11-29 10:39:24 -05:00
|
|
|
|
|
|
|
In common cases, lifetimes can be elided, as described on the next slide.
|
|
|
|
|
|
|
|
</details>
|