У меня есть следующий код
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), это невозможно. Вот мои рассуждения:
add_vectors
получает сами векторы, а не ссылки. Следовательно, он берет на себя ответственность за них.add_vectors
явно создается и возвращается новый Vector3D::<f64,Unit>
.add_vectors
достигает конца, a
и b
выходят за пределы области видимости, поэтому они удаляются.v1
и v2
больше не существует.(Я только изучаю Rust, извините, если ответ слишком очевиден, и я его не вижу.)
Точнее, это Copy
тогда и только тогда, когда T
есть Copy
: docs.rs/euclid/latest/src/euclid/vector.rs.html#924 что f64
есть.
Значит, если T
реализует черту Copy
, то так оно и будет euclid::Vector3D
и будет вести себя точно так же? Копирование — это черта или что-то еще?
Copy
— признак маркера, который сообщает компилятору, что источник не становится недействительным при перемещении и может использоваться после его перемещения (в субструктурных терминах он меняет тип с аффинного на нормальный)
@Masklinn, это неверно, источник нельзя использовать после перемещения. Copy
сообщает компилятору, что тип можно побитно скопировать (в другую область памяти).
@RichardNeumann это всего лишь две стороны одной медали. Перемещение также является побитовой копией (если только компилятор не может ее удалить) и помечает исходное значение как недействительное.
@RichardNeumann Побитовое копирование — это именно то, что делает ход. Как я уже писал, Copy
сообщает компилятору, что исходный код все еще действителен (или, если хотите, !Copy
сообщает компилятору, что исходный код недействителен), вот и все.
Вы оба правы. У меня было заблуждение, что перемещение передает фактическое право собственности на область памяти в стеке, но это, очевидно, не так: google.github.io/comprehensive-rust/memory-management/move.html
Большинство типов euclid
являются Copy
, если базовым T
является Copy
. Это означает, что они не перемещаются из исходного местоположения, а просто копируются.
euclid::Vector3D
— этоCopy
, тогда вызов функции не перемещаетv1
иv2
в параметры, а копирует их (как если бы они были простыми целыми числами, например).