Не могу понять, почему этот код работает согласно правилам владения

У меня есть следующий код

use euclid::Vector3D;

fn main() {
    fn add_vectors<Unit>(a: Vector3D::<f64, Unit>, b: Vector3D::<f64, Unit>) -> Vector3D::<f64, Unit> {
        // I take ownership of `a` and `b`.
        Vector3D::<f64,Unit>::new(a.x+b.x, a.y+b.y, a.z+b.z) // Explicitly create a new vector, and return it together with its ownership.
    } // `a` and `b` go out of scope, they are dropped.
    enum Meters {}
    let v1 = Vector3D::<f64,Meters>::new(1., 2., 3.);
    let v2 = Vector3D::<f64,Meters>::new(1., 2., 3.);
    // Up to here, `main` is the owner of `v1` and `v2`.
    println!("Added: {:?}", add_vectors(v1,v2)); // Ownership is transferred to `add_vectors`.
    println!("Original vectors: {:?} and {:?}", v1, v2); // `v1` and `v2` should have been dropped by now.
}

который компилируется без предупреждений и запускается, как и следовало ожидать в Python. Однако это Rust, и я не понимаю, как второй println! может использовать v1 и v2, учитывая, что, согласно моему пониманию из владения (Rust book), это невозможно. Вот мои рассуждения:

  1. add_vectors получает сами векторы, а не ссылки. Следовательно, он берет на себя ответственность за них.
  2. В теле add_vectors явно создается и возвращается новый Vector3D::<f64,Unit>.
  3. Когда add_vectors достигает конца, a и b выходят за пределы области видимости, поэтому они удаляются.
  4. Теперь v1 и v2 больше не существует.

(Я только изучаю Rust, извините, если ответ слишком очевиден, и я его не вижу.)

euclid::Vector3D — это Copy, тогда вызов функции не перемещает v1 и v2 в параметры, а копирует их (как если бы они были простыми целыми числами, например).
prog-fh 09.04.2024 09:30

Точнее, это Copy тогда и только тогда, когда T есть Copy: docs.rs/euclid/latest/src/euclid/vector.rs.html#924 что f64 есть.

Richard Neumann 09.04.2024 09:30

Значит, если T реализует черту Copy, то так оно и будет euclid::Vector3D и будет вести себя точно так же? Копирование — это черта или что-то еще?

user171780 09.04.2024 09:32
Copy — признак маркера, который сообщает компилятору, что источник не становится недействительным при перемещении и может использоваться после его перемещения (в субструктурных терминах он меняет тип с аффинного на нормальный)
Masklinn 09.04.2024 09:39

@Masklinn, это неверно, источник нельзя использовать после перемещения. Copy сообщает компилятору, что тип можно побитно скопировать (в другую область памяти).

Richard Neumann 09.04.2024 09:41

@RichardNeumann это всего лишь две стороны одной медали. Перемещение также является побитовой копией (если только компилятор не может ее удалить) и помечает исходное значение как недействительное.

cafce25 09.04.2024 10:34

@RichardNeumann Побитовое копирование — это именно то, что делает ход. Как я уже писал, Copy сообщает компилятору, что исходный код все еще действителен (или, если хотите, !Copy сообщает компилятору, что исходный код недействителен), вот и все.

Masklinn 09.04.2024 11:00

Вы оба правы. У меня было заблуждение, что перемещение передает фактическое право собственности на область памяти в стеке, но это, очевидно, не так: google.github.io/comprehensive-rust/memory-management/move.h‌​tml

Richard Neumann 09.04.2024 12:48
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
9
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Большинство типов euclid являются Copy, если базовым T является Copy. Это означает, что они не перемещаются из исходного местоположения, а просто копируются.

Другие вопросы по теме