Компилятор Rust достаточно умен, чтобы видеть, когда используется только одно поле структуры. Право собственности передано только этому конкретному полю, а остальные поля удаляются в конце области (или используются иным образом). Это можно увидеть в следующем примере.
struct MyObject {
a: String,
b: String,
c: String,
}
fn consume_string(_string: String) {}
fn main() {
let object = MyObject {
a: "".to_string(),
b: "".to_string(),
c: "".to_string(),
};
consume_string(object.b);
// We can still access object.a and object.c
println!("{}", object.a);
println!("{}", object.c);
// but not object.b
// println!("{}", object.b);
}
(детская площадка)
Однако, если структура имеет нетривиальный деструктор, т. Е. Реализует Drop
черта, тогда этого не может быть. Попытка переместить одно поле структуры приведет к ошибке компилятора, как показано ниже.
struct MyObject {
a: String,
b: String,
c: String,
}
// This is new
impl Drop for MyObject {
fn drop(&mut self) {
println!("dropping MyObject");
}
}
fn consume_string(_string: String) {}
fn main() {
let object = MyObject {
a: "".to_string(),
b: "".to_string(),
c: "".to_string(),
};
consume_string(object.b);
}
Попытка скомпилировать это приводит к ошибке
error[E0509]: cannot move out of type `MyObject`, which implements the `Drop` trait
--> src/main.rs:22:20
|
22 | consume_string(object.b);
| ^^^^^^^^
| |
| cannot move out of here
| move occurs because `object.b` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to previous error
For more information about this error, try `rustc --explain E0509`.
error: Could not compile `playground`.
(детская площадка) ( [E0509] )
Я думаю, вы уже поняли причину этого, но стоит повторить. Если Drop
реализовано для структуры, деструктор может иметь нетривиальные взаимодействия между полями;они не могут быть просто отброшены независимо друг от друга. Таким образом, это означает, что структура должна оставаться единым целым до тех пор, пока она не будет отброшена.
Например, реализация Drop
для Rc<T>
проверяет, есть ли какие-либо (сильные) ссылки на оставленные данные, иесли нет, удаляет базовые данные. Если бы поля Rc<T>
(указатель, счетчик сильных ссылок и счетчик слабых ссылок) были удалены отдельно, невозможно было бы проверить, сколько сильных ссылок осталось при удалении указателя. Не будет никакого способа сохранить исходные данные, если все еще будут сильные ссылки.
Как вы уже догадались, в случае реализации Drop
вам придется клонировать поле, если вы все ещехотел потреблять это.