Система владения (ownership) — это основная концепция Rust для обеспечения безопасности памяти на уровне компиляции. У каждой переменной есть владелец. Только один владелец ресурса может существовать в определённый момент времени.
Владение передаётся (move) при присваивании или передаче в функцию. После передачи прежний владелец не может использовать значение:
let s = String::from("hello"); let t = s; // s больше недоступен
Rust также различает заимствование (ссылки).
&T — ссылка только для чтения (borrow).&mut T — изменяемая ссылка (mutable borrow), но только одна может быть в одном времени жизни.С помощью этих правил Rust гарантирует, что не возникнет гонок данных, используемых после освобождения памяти и других ошибок управления ресурсами.
Может ли быть более одной изменяемой ссылки (&mut T) одновременно у одного значения? Почему?
Ответ: Нет, в каждый момент времени может быть либо любое количество неизменяемых ссылок, либо только одна изменяемая. Это предотвращает гонки данных. Пример неверного кода:
let mut s = String::from("hi"); let r1 = &mut s; let r2 = &mut s; // ошибка компиляции!
История
В одном мультипоточном проекте разработчик пытался хранить ссылки на изменяемый буфер, не используя владение, что приводило к сбоям (use-after-free), когда буфер освобождался до завершения работы со ссылкой. Rust не позволил скомпилировать такой код, поэтому пришлось изменить архитектуру.
История
На старте большого проекта Rust программисты мигрировали код с C++. Они пытались совместить устаревшие привычки работы с "сырыми" указателями, что приводило к ошибкам с владением ресурсами и постоянным паникам borrow checker'а, пока не была решена архитектурная проблема владения.
История
В библиотеке парсинга строк ошибки с двойным освобождением памяти удалось избежать только благодаря строгой системе владения Rust. Аналогичная библиотека на C++ приводила к трудноловимым багам и утечкам памяти.