3. Владение (Ownership)
В Rust используется концепция владения (ownership) данными. Это некий набор разумных правил, предназначенных для обеспечения безопасной работы с памятью.
Суть владения
Напомню, в программе объявляются переменные, значения которых хранятся в оперативной памяти. В Rust у каждого значения есть единственная переменная-владелец. Владелец значения может и поменяться, но правило неизменно. В один момент времени, существует только одна переменная-владелец этого значения.
Соответственно, после того, как переменная, владеющая этими данными станет не нужна, переменная удаляется и память, содержащая данные, которыми она владела, освобождается.
А как определить, что переменная больше не нужна? Очень просто, когда она вышла за пределы области видимости.
Область видимости
Область видимости мы уже рассматривали в первом курсе в материале про переменные. Напомню, что переменные доступны для использования только внутри своего блока кода ограниченного фигурными скобками. Как только программа вышла за этот блок кода, все переменные, находящиеся внутри него, Rust удаляет и освобождает память.
Копирование и перемещение
Часто требуется значение одной переменной передать другой переменной. В зависимости от типа данных этой переменной, значение может быть скопировано (продублировано в памяти) или перемещено (отдано во владение другой переменной).
Копирование данных
Рассмотрим пример с числами:
fn main() {
let n = 8;
let m = n;
println!("m = {}", m);
println!("n = {}", n);
}
Во второй строке программы переменную

Иными словами, переменная
Копирование это самое простое и очевидное решение. Но копирование разумно использовать только с простыми типами данных. Такие данные имеют фиксированный, заранее известный размер, хранятся в стеке и затраты на их копирование в памяти невелики.
Перечень копируемых типов данных (Copy Type):
- Целочисленные типы,
- числа с плавающей запятой,
- bool,
- char,
- фиксированная строка &str,
- а также кортежи и массивы (содержащие в себе исключительно вышеназванные типы).
Перемещение данных
А вот пример со строками работает по другому:
fn main() {
let s: String = String::from("Пример");
let t: String = s;
println!("t = {}", t);
println!("s = {}", s);
}
Переменную
В следующей лекции мы избавимся от ошибки в данном примере.
Схема перемещения данных:

Вторая переменная забирает во владение значение первой перменной, хранящейся в памяти компьютера, а первая становится недоступна
Данные непримитивных типов могут иметь произвольный размер и хранятся в куче, затраты на их копирование в памяти велики, поэтому они перемещаются. Примеры таких типов (Move Type):
- String Objects,
- Vector,
- а также кортежи и массивы (содержащие в себе вышеназванные типы).
Приведем образные примеры копирования и перемещения в виде следующих историй:
У Егора возникла идея и он рассказал её Нине.
fn main() {
let i_egor: &str = "идея";
let i_nina: &str = i_egor; // Егор поделился идеей с Ниной
println!("У Нины появилась {}", i_nina);
println!("У Егора осталась {}", i_egor);
}
А в другой ситуации Егор отдает Нине книгу
fn main() {
let real_egor: String = "книга".to_string();
let real_nina: String = real_egor; // Егор отдал книгу Нине
println!("У Нины появилась {}", real_nina);
//println!("У Егора осталась {}", real_egor); // Ошибка, значение передано другой переменной.
println!("У Егора теперь нет книги");
}
Не стоит воспринимать эти примеры серьёзно. Разница обусловлена, конечно же, не значением переменной. Программе не важно это “идея” или “книга”. Важен тип данных.
Клонирование данных
Что делать, если все-таки захочется сделать дубликат данных первой переменной, даже если мы используем перемещаемый тип данных? Для этого есть метод
В нашем шуточном примере пусть Егор оставит у себя свою книгу, а для Нины отсканирует и распечатает идентичную копию.
fn main() {
let real_egor: String = "книга".to_string();
let real_nina: String = real_egor.clone(); // Егор отдал копию книги Нине
println!("У Нины появилась {}", real_nina);
println!("У Егора осталась {}", real_egor);
}
Копирование и перемещение данных в функцию
В функциях все происходит по аналогии как с переменными. Если тип данных простой, то при передаче в функцию, он копируется в её переменную, а если сложный, то перемещается.
fn main() {
let x: i8 = 5;
use_var(x);
println!("Значение х в main: {}",x);
}
fn use_var(var: i8) {
println!("Значение х, переданное в use_var: {}", var);
}
Здесь значение переменной
Попробуем проделать то же самое со строкой.
fn main() {
let s: String = "Учиться легко".to_string();
use_str_var(s);
println!("Значение s в main: {}",s);
}
fn use_str_var(var: String) {
println!("Значение s, переданное в use_str_var: {}", var);
}
Как мы и ожидали, значение переменной
Но что же делать, если нас не устраивает данная ситуация? Как решить проблему?
Антипример
Давайте попробуем использовать переданную переменную и вернуть использованное значение обратно.
fn main() {
let mut s: String = "Учиться легко".to_string();
s = use_str_var(s);
println!(Значение х в main: {}", s);
}
fn use_str_var(var: String) -> String {
println!("Значение s, переданное в use_str_var: {}", var);
var
}
В этом примере мы сделали “финт ушами”. В прошлом примере мы просто вызвали функцию, которая как-то использовала
Мы вроде своего добились, но этот код просто ужасен. Надеюсь вы понимаете, как это уродливо и как потом тяжело искать логику в подобных ситуациях. Нам нужно другое решение.
Если пойти по простому пути, то можно клонировать значение переменной s:
fn main() {
let s: String = "Учиться легко".to_string();
use_str_var(s.clone());
println!("Значение s в main: {}",s);
}
fn use_str_var(var: String) {
println!("Значение s, переданное в use_str_var: {}", var);
}
В данном примере, происходит единоразовое клонирование короткой строку. А если в вашей программе это будет происходить много раз и строки будут длинными, то такой метод уже не пройдет, поэтому давайте изучать следующие возможности языка программирования Rust.
Для просмотра заданий и решений, а также публикации своих решений необходимо зарегистрироваться на сайте.
Всё бесплатно, мы просто хотим с вами познакомиться и понять насколько актуально то, что мы делаем.