Что это такое и как их использовать?
Я изучаю Rust и сделал несколько заметок о концепциях Ownership
и Borrowing
.
Обратите внимание, что я все еще пытаюсь понять эти концепции, одновременно «борясь с программой проверки заимствований Rust» ...
Право собственности в Rust
Владение = привязка / ассоциация значения с переменной. Правила следующие:
- Только один владелец за раз.
- Если привязка «освобождена», право собственности «уходит» и данные «освобождаются».
let p1 = Person::new(); //1 p2 = p1; //2
let p1 = Person::new(); do_something(p1); //out of scope
В строке 2 будет освобождено p1
. Это выходит за рамки, поскольку он передал право собственности на p2
. Передача p1
в другую функцию также имеет тот же эффект.
let p1 = Person::new();
p2 = p1;
println!("person {#:?}", p2)
println!("person {#:?}", p1) //compile error
По этой причине Rust не позволяет вам снова использовать это значение. Он обеспечивает это во время компиляции с помощью средства проверки заимствований.
Drop
Если требуется настраиваемая логика очистки, можно реализовать метод drop
из трейта Drop
. Он будет автоматически вызван Rust, когда это значение выйдет за пределы области видимости.
Как только переменная выходит за пределы области видимости, т. Е. Ее владение было прекращено, компилятор Rust не позволит вам использовать ее снова, поскольку ее необходимо «освободить». Это также называется Moving
, т.е. право собственности на p1
перемещено в p2
.
Право собственности применимо только к данным кучи, не к данным стека, поскольку они (данные стека) «копируются», а не «перемещаются».
Copy
Признак Copy
позволяет копировать значение. Все примитивные типы (например, i32
, bool
и т. Д.) Реализуют Copy
неявно.
Пользовательские типы (например, struct
s) могут реализовывать Copy
, если все его компоненты также реализуют Copy
. Для реализации вы можете использовать #[derive(Copy)]
или использовать явную реализацию
Способы перехода в собственность
И чтобы компилятор был доволен.
- Используйте метод
clone()
. - Возврат из функции.
- Передача ссылки.
- Передача изменяемой ссылки.
Используйте clone ()
Думайте об этом как об операции, подобной deep copy
, когда она создает отдельную копию данных в куче и указывает на нее новому владельцу, оставляя старое значение нетронутым (или неизменным).
Некоторые типы реализуют черту Clone
по умолчанию (например, String
), но вы можете пометить свои настраиваемые типы как клонируемые с помощью #[derive(Clone)]
.
let p1 = Person::new();
let p2 = p1.clone();
do_something(p2);
println!("{:?}, p1); //works ok
Возврат из функции
let p1 = Person::new(); do_something(p1); ...
fn do_something(p: Person) -> Person { //logic }
...
println!("p = {}",p1); //continue using p1 since ownership has been passed back
Но это просто странно! Вы вынуждены что-то возвращать только потому, что хотите сохранить переменную в области видимости.
Передача ссылки
let p1 = Person::new(); do_something(&p1); println!("p = {}",p1); //continue using p1 since ownership has been was never passed on ...
fn do_something(p: &Person) { //logic }
...
Значение p1
не перемещалось - это называется Borrowing
. do_something
так и не получил права собственности, так как все, что мы сделали, это передали ссылку на p1
- обратите внимание на &
.
Изменяемые ссылки
Если вы хотите, чтобы логика do_something
обновляла имя ссылки Person
, вам необходимо передать изменяемую ссылку.
let mut p1 = Person::new(); do_something(&mut p1); println!("mutated info {}",p2) ...
fn do_something(p: &mut Person, new_name: String) { p.name = String::from(new_name); } ...
Изменения:
- Переменная
p1
была объявлена какmut
(изменяемая). - Передано
&mut
вdo_something
вместо просто&
- означает изменяемую ссылку. - Подпись
do_something
обновлена до&mut
- означает изменяемую ссылку.
Заключение
Чтобы погрузиться в подробности, вы можете прочитать следующие главы из книги Язык программирования Rust.