Владение (ownership)
Кратко
Для данных в куче let b = a; выполняет только поверхностное копирование, при этом a становится invalid и недоступной (то есть происходит move)
Нужно писать let b = a.clone();, чтобы получить глубокое копирование; в этом случае a остаётся доступной
Если тип входного параметра функции объявлен как String, произойдёт поверхностное копирование (переданное значение перемещается), а если используется reference (&String), перемещения не будет
(процесс создания reference называется borrowing)
Если нужно изменить значение через reference, входной параметр должен быть объявлен как &mut String
В один и тот же момент для одних и тех же исходных данных
может существовать только один &mut reference (изменяемый), или
может существовать несколько & reference (неизменяемых).
Запрещено: в пределах scope reference одновременно иметь let &b = a и let mut &c = a, то есть нельзя одновременно borrow неизменяемый и изменяемый reference
reference гарантированно valid на этапе компиляции, поэтому Dangling References не возникнет
В Rust есть аннотация trait, пока не знаю, что это
Источник
https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html
…
У Rust есть специальная аннотация — трейт Copy, — которую можно ставить на типы вроде целых чисел, хранящихся в стеке (подробнее о трейтах в главе 10). Если тип реализует трейт Copy, старая переменная остаётся пригодной после присваивания. Rust не позволит аннотировать тип трейтом Copy, если сам тип или любая его часть реализует трейт Drop. Если типу нужно что-то особенное при выходе значения из области видимости, а мы добавим этому типу аннотацию Copy, то получим ошибку времени компиляции. О том, как добавить аннотацию Copy к своему типу, см.
«Derivable Traits»
в приложении C.
Так какие типы реализуют трейт Copy? Это можно проверить в документации конкретного типа, но общее правило такое: любая группа простых скалярных значений может реализовать Copy, а всё, что требует выделения памяти или является неким ресурсом, реализовать Copy не может. Вот некоторые типы, реализующие Copy:
- Все целочисленные типы, например
u32. - Логический тип
boolсо значениямиtrueиfalse. - Все типы с плавающей точкой, например
f64. - Символьный тип
char. - Кортежи, если они содержат только типы, которые тоже реализуют
Copy. Например,(i32, i32)реализуетCopy, а(i32, String)— нет.
…
Имя файла: src/main.rs
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
println!("{}, {}", r1, r2);
Вот ошибка:
$ cargo run
Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0499]: cannot borrow `s` as mutable more than once at a time
--> src/main.rs:5:14
|
4 | let r1 = &mut s;
| ------ first mutable borrow occurs here
5 | let r2 = &mut s;
| ^^^^^^ second mutable borrow occurs here
6 |
7 | println!("{}, {}", r1, r2);
| -- first borrow later used here
For more information about this error, try `rustc --explain E0499`.
error: could not compile `ownership` due to previous error
Эта ошибка говорит, что код недопустим, потому что мы не можем заимствовать s как изменяемую более одного раза одновременно. Первое изменяемое заимствование находится в r1 и должно длиться до его использования в println!, но между созданием этой изменяемой ссылки и её использованием мы попытались создать в r2 ещё одну изменяемую ссылку, заимствующую те же данные, что и r1.
…
Как всегда, мы можем использовать фигурные скобки, чтобы создать новую область видимости и тем самым получить несколько изменяемых ссылок — просто не одновременных:
let mut s = String::from("hello");
{
let r1 = &mut s;
} // r1 goes out of scope here, so we can make a new reference with no problems.
let r2 = &mut s;
Похожее правило действует и для сочетания изменяемых и неизменяемых ссылок. Этот код приводит к ошибке:
let mut s = String::from("hello");
let r1 = &s; // no problem
let r2 = &s; // no problem
let r3 = &mut s; // BIG PROBLEM
println!("{}, {}, and {}", r1, r2, r3);
Вот ошибка:
$ cargo run
Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
--> src/main.rs:6:14
|
4 | let r1 = &s; // no problem
| -- immutable borrow occurs here
5 | let r2 = &s; // no problem
6 | let r3 = &mut s; // BIG PROBLEM
| ^^^^^^ mutable borrow occurs here
7 |
8 | println!("{}, {}, and {}", r1, r2, r3);
| -- immutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `ownership` due to previous error
Уф! Мы также не можем иметь изменяемую ссылку, пока у нас есть неизменяемая. Пользователи неизменяемой ссылки не ожидают, что значения внезапно изменятся у них под руками! Впрочем, несколько неизменяемых ссылок допустимы, потому что тот, кто только читает данные, не может повлиять на чтение данных кем-то другим.
Заметим, что область видимости ссылки начинается с того места, где она введена, и продолжается до последнего её использования. Например, этот код скомпилируется, потому что последнее использование неизменяемых ссылок, println!, происходит до введения изменяемой ссылки:
let mut s = String::from("hello");
let r1 = &s; // no problem
let r2 = &s; // no problem
println!("{} and {}", r1, r2);
// variables r1 and r2 will not be used after this point
let r3 = &mut s; // no problem
println!("{}", r3);
…
Правила ссылок
Подведём итог сказанному о ссылках:
- В любой момент времени у вас может быть либо одна изменяемая ссылка, либо любое количество неизменяемых ссылок.
- Ссылки всегда должны быть валидными.