Модульні уроки (1/2)
Правила власності
Право власності є найбільш унікальною рисою Rust. Це дозволяє мові гарантувати безпеку пам’яті, не потребуючи збирача сміття або змушуючи вас вручну звільняти пам’ять купи (як у C або C++).
Три правила власності
Керування пам’яттю в Rust регулюється трьома простими правилами, які суворо перевіряються компілятором:
- Кожне значення в Rust має змінну, яка називається власником.
- Одночасно може бути лише один власник.
- Коли власник виходить за межі області, значення автоматично видаляється.
Стек проти купи
Щоб зрозуміти право власності, важливо знати, де зберігаються дані:
- Стек: зберігає дані фіксованого розміру, відомі під час компіляції (наприклад, цілі числа, логічні значення). Доступ надзвичайно швидкий.
- Куча: зберігає дані динамічного розміру, невідомі під час компіляції (наприклад,
String). Розподіл відбувається повільніше та потребує покажчика, що зберігається в стеку.
Поняття «рух»
Коли ми призначаємо змінну, виділену в купі, іншій, Rust переміщує (або передає) право власності на значення, роблячи першу змінну недійсною:
let s1 = String::from("ciao");
let s2 = s1; // Ownership of the text moves to s2. s1 is NO longer usable!
// println!("{}", s1); // COMPILATION ERROR! s1 is "borrow of moved value"
println!("{}", s2); // Valid!Така поведінка дозволяє уникнути "помилки подвійного звільнення" (спроба звільнити ту саму пам'ять двічі при виході за межі області), оскільки лише s2 звільнить пам'ять.
Концепція «Клон» (Deep Copy)
Якщо нам явно потрібно скопіювати весь вміст String (як покажчики стека, так і фактичні текстові дані в купі), ми можемо використати метод .clone(). Це повністю дублює дані в купі, зберігаючи дійсними як початкову, так і нову змінну, ціною накладних витрат на продуктивність для нового розподілу пам’яті:
let s1 = String::from("ciao");
let s2 = s1.clone(); // Deep copy. Both variables remain valid!
println!("s1: {}, s2: {}", s1, s2);Поняття «копія»
Для простих типів, які повністю зберігаються в Стеку (як-от цілі числа i32, логічні значення bool, символи char), призначення виконує фактичне автоматичне дрібне копіювання, тобто обидві змінні залишаються дійсними:
let x = 5;
let y = x; // Copies the value 5 onto the stack. Both variables are usable!
println!("x: {}, y: {}", x, y); // Valid!Спробуйте самі
Оголошіть рядок s1, що містить текст «hello». Призначте s1 до s2 (щоб перенести право власності). Нарешті, надрукуйте s2 за допомогою println!.
Показати підказку
Використовуйте `let s2 = s1;`, щоб передати право власності на `s2` і надрукуйте його за допомогою `println!('{}', s2);`.
Рішення доступне після 3 спроб
Оголошіть цілочисельну змінну x зі значенням 5. Призначте x до y (виконуючи копіювання). Нарешті, надрукуйте x і y в одному println! заява.
Показати підказку
Виконайте `let y = x;`, а потім виведіть обидва значення, наприклад, `println!('{} {}', x, y);`.
Рішення доступне після 3 спроб
Declare a String s1 with the value "Rust". Create a deep copy of s1 in a new variable s2 using the clone method. Finally, print both s1 and s2 separated by a space using the println! macro.
Показати підказку
Use `let s2 = s1.clone();` to deep copy the value of `s1` into `s2`, then print them with `println!("{} {}", s1, s2);`.
Рішення доступне після 3 спроб