Что это такое и как их использовать?

Я изучаю 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 неявно.

Пользовательские типы (например, structs) могут реализовывать 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.