Заимствование одного
В этом примере find_nearest принимает несколько заимствований, но возвращает только одно из них. Аннотации времён жизни явно связывают возвращаемое заимствование с соответствующим заимствованием аргумента.
// Copyright 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0
#[derive(Debug)]
struct Point(i32, i32);
/// Ищет в `points` точку, ближайшую к `query`.
/// Предполагается, что в `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.expect("at least one point expected").0
// query // Что будет, если сделать вот так?
}
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` в этот момент не заимствуется.
drop(query);
dbg!(nearest);
}
-
Может помочь свернуть определение
find_nearest, чтобы сделать акцент на сигнатуре функции. Реальная логика функции довольно сложна и для анализа заимствований не важна. -
Когда мы вызываем
find_nearest, возвращённая ссылка не заимствуетquery, поэтому мы свободны освободить его, покаnearestещё активна. -
Но что будет, если вернуть неправильное заимствование? Измените последнюю строку
find_nearest, чтобы она возвращалаquery. Покажите студентам ошибку компилятора. -
Первое, что нужно сделать, — добавить аннотацию времени жизни к
query. Покажите студентам, что мы можем добавить второе время жизни'bкfind_nearest. -
Покажите новую ошибку студентам. Анализатор заимствований проверяет, что логика тела функции действительно возвращает ссылку с правильным временем жизни, обеспечивая соответствие функции контракту, заданному её сигнатурой.
Для дальнейшего изучения
-
В сообщении «help» сказано, что мы можем добавить ограничение времени жизни
'b: 'a, чтобы указать, что'bбудет жить не меньше, чем'a, что позволит вернутьquery. Это пример подтипизации времён жизни (lifetime subtyping), которая позволяет вернуть более долгое время жизни там, где ожидается более короткое. -
Похожее можно сделать, вернув время жизни
'static, например ссылку на переменнуюstatic. Время жизни'staticгарантированно длиннее любого другого, поэтому его всегда безопасно возвращать вместо более короткого.