Borrow One
In this example find_nearest takes in multiple borrows but returns only one of
them. The lifetime annotations explicitly tie the returned borrow to the
corresponding argument borrow.
#[derive(Debug)] struct Point(i32, i32); /// Searches `points` for the point closest to `query`. /// Assumes there's at least one point in `points`. fn find_nearest<'a>(points: &'a [Point], query: &Point) -> &'a Point { fn cab_distance(p1: &Point, p2: &Point) -> i32 { (p1.0 - p2.0).abs() + (p1.1 - p2.1).abs() } let mut nearest = None; for p in points { if let Some((_, nearest_dist)) = nearest { let dist = cab_distance(p, query); if dist < nearest_dist { nearest = Some((p, dist)); } } else { nearest = Some((p, cab_distance(p, query))); }; } nearest.map(|(p, _)| p).unwrap() // query // What happens if we do this instead? } fn main() { let points = &[Point(1, 0), Point(1, 0), Point(-1, 0), Point(0, -1)]; let query = Point(0, 2); let nearest = find_nearest(points, &query); // `query` isn't borrowed at this point. drop(query); dbg!(nearest); }
-
It may be helpful to collapse the definition of
find_nearestto put more focus on the signature of the function. The actual logic in the function is somewhat complex and isn’t important for the purpose of borrow analysis. -
When we call
find_nearestthe returned reference doesn’t borrowquery, and so we are free to drop it whilenearestis still active. -
But what happens if we return the wrong borrow? Change the last line of
find_nearestto returnqueryinstead. Show the compiler error to the students. -
The first thing we have to do is add a lifetime annotation to
query. Show students that we can add a second lifetime'btofind_nearest. -
Show the new error to the students. The borrow checker verifies that the logic in the function body actually returns a reference with the correct lifetime, enforcing that the function adheres to the contract set by the function’s signature.
-
The “help” note in the error notes that we can add a lifetime bound
'b: 'ato say that'bwill live at least as long as'a, which would then allow us to returnquery. On the next slide we’ll talk about lifetime variance, which is the rule that allows us to return a longer lifetime when a shorter one is expected.