diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 3f620c18afa7..ed6a92a1fcc1 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -171,7 +171,7 @@ - [Lifetimes](lifetimes.md) - [Lifetime Annotations](lifetimes/lifetime-annotations.md) - [Lifetime Elision](lifetimes/lifetime-elision.md) - - [Struct Lifetimes](lifetimes/struct-lifetimes.md) + - [Lifetimes in Data Structures](lifetimes/struct-lifetimes.md) - [Exercise: Protobuf Parsing](lifetimes/exercise.md) - [Solution](lifetimes/solution.md) diff --git a/src/lifetimes/lifetime-annotations.md b/src/lifetimes/lifetime-annotations.md index d1df6e7957e2..2b9a0ffda323 100644 --- a/src/lifetimes/lifetime-annotations.md +++ b/src/lifetimes/lifetime-annotations.md @@ -12,12 +12,14 @@ 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`". -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. +Only ownership, not lifetime annotations, control when values are destroyed and +determine the concrete lifetime of a given value. The borrow checker just +validates that borrows never extend beyond the concrete lifetime of the value. -Lifetimes become more complicated when considering passing values to and -returning values from functions. +Explicit lifetime annotations, like types, are required on function signatures +(but can be elided in common cases). These provide information for inference at +callsites and within the function body, helping the borrow checker to do its +job. @@ -56,9 +58,11 @@ Add `'a` appropriately to `left_most`: fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point { ``` -This says, "given p1 and p2 which both outlive `'a`, the return value lives for -at least `'a`. +This says there is some lifetime `'a` which both `p1` and `p2` outlive, and +which outlives the return value. The borrow checker verifies this within the +function body, and uses this information in `main` to determine a lifetime for +`p3`. -In common cases, lifetimes can be elided, as described on the next slide. +Try dropping `p2` in `main` before printing `p3`. diff --git a/src/lifetimes/lifetime-elision.md b/src/lifetimes/lifetime-elision.md index fdfeaceeded2..c996813f70f4 100644 --- a/src/lifetimes/lifetime-elision.md +++ b/src/lifetimes/lifetime-elision.md @@ -23,7 +23,7 @@ fn cab_distance(p1: &Point, p2: &Point) -> i32 { (p1.0 - p2.0).abs() + (p1.1 - p2.1).abs() } -fn nearest<'a>(points: &'a [Point], query: &Point) -> Option<&'a Point> { +fn find_nearest<'a>(points: &'a [Point], query: &Point) -> Option<&'a Point> { let mut nearest = None; for p in points { if let Some((_, nearest_dist)) = nearest { @@ -40,7 +40,11 @@ fn nearest<'a>(points: &'a [Point], query: &Point) -> Option<&'a Point> { fn main() { let points = &[Point(1, 0), Point(1, 0), Point(-1, 0), Point(0, -1)]; - println!("{:?}", nearest(points, &Point(0, 2))); + let nearest = { + let query = Point(0, 2); + find_nearest(points, &Point(0, 2)) + }; + println!("{:?}", nearest); } ``` @@ -49,12 +53,13 @@ fn main() { In this example, `cab_distance` is trivially elided. The `nearest` function provides another example of a function with multiple -references in its arguments that requires explicit annotation. +references in its arguments that requires explicit annotation. In `main`, the +return value is allowed to outlive the query. Try adjusting the signature to "lie" about the lifetimes returned: ```rust,ignore -fn nearest<'a, 'q>(points: &'a [Point], query: &'q Point) -> Option<&'q Point> { +fn find_nearest<'a, 'q>(points: &'a [Point], query: &'q Point) -> Option<&'q Point> { ``` This won't compile, demonstrating that the annotations are checked for validity