Повторное использование привязки в закрытии Rust

Я пытаюсь создать Vec<(Point, f64)>:

let grid_size = 5;

let points_in_grid = (0..grid_size).flat_map(|x| {
    (0..grid_size)
        .map(|y| Point::new(f64::from(x), f64::from(y)))
        .collect::<Vec<Point>>()
});

let origin = Point::origin();

let points_and_distances = points_in_grid
    .map(|point| (point, point.distance_to(&origin)))
    .collect::<Vec<(Point, f64)>>();

Я получаю следующую ошибку:

use of moved value: point

Я понимаю, что не могу использовать point в обоих элементах кортежа, но когда я пытаюсь сохранить ссылку, я получаю сообщение об ошибке времени жизни.


person davenportw15    schedule 26.11.2016    source источник
comment
Не могли бы вы предоставить полный компилируемый (даже с ошибкой) пример, желательно, который будет работать на play.rust-lang.org? Было бы проще узнать, какую ошибку вы получаете и где, и предложить решение.   -  person Chris Emerson    schedule 26.11.2016


Ответы (1)


Я предполагаю, что ваша структура Point выглядит следующим образом:

#[derive(Debug)]
struct Point(f64, f64);

impl Point {
    fn new(x: f64, y: f64) -> Self { Point(x, y) }
    fn origin() -> Self { Point(0.,0.) }
    fn distance_to(&self, other: &Point) -> f64 {
        ((other.0 - self.0).powi(2) + (other.1 - self.1).powi(2)).sqrt()
    }
}

Теперь давайте посмотрим на еще более простой пример, который не компилируется:

let x = Point::new(2.5, 1.0);
let y = x;
let d = x.distance_to(&y);

Что дает ошибку:

error[E0382]: use of moved value: `x`
  --> <anon>:15:13
   |
14 |     let y = x;
   |         - value moved here
15 |     let d = x.distance_to(&y);
   |             ^ value used here after move
   |
   = note: move occurs because `x` has type `Point`, which does not implement the `Copy` trait

Поскольку x был перемещен в y, теперь он не может иметь ссылку для вызова функции distance_to.

Здесь важно отметить, что порядок имеет значение - если мы поменяем местами строки, мы сможем вызвать distance_to, заимствовав x, заимствование закончится, и затем x можно будет переместить в y.

let x = Point(0., 0.);
let d = x.distance_to(&y);
let y = x; // compiles

В вашем случае очень похожая вещь происходит при построении кортежа. point перемещается в кортеж, и затем пытается заимствовать его, чтобы сформировать второй элемент. Самое простое решение - сделать то же самое, что и здесь: поменять местами элементы кортежа.

let points_and_distances = points_in_grid
    .map(|point| (point.distance_to(&origin), point))
    .collect::<Vec<(f64, Point)>>(); // compiles

Ссылка на игровую площадку

N.B. если вы хотите сохранить заказ:

.map(|(a, b)| (b, a))
person Djzin    schedule 26.11.2016
comment
Другими словами, Point не реализует Copy. Вы также можете использовать временную переменную - .map(|point| { let d = point.distance_to(&origin); (point, d) }). - person Shepmaster; 26.11.2016