RAII
Змінні в Rust роблять більше, ніж просто зберігають дані в стеку: вони також володіють
ресурсами, наприклад, Box<T> володіє пам’яттю в купі. Rust забезпечує RAII
(Resource Acquisition Is Initialization), тож коли об’єкт виходить із
області видимості, викликається його деструктор, і його власні ресурси звільняються.
Ця поведінка захищає від помилок витоку ресурсу — тому вам більше ніколи не доведеться вручну звільняти пам’ять або турбуватися про витоки пам’яті! Ось коротка демонстрація:
// raii.rs
fn create_box() {
// Allocate an integer on the heap
let _box1 = Box::new(3i32);
// `_box1` is destroyed here, and memory gets freed
}
fn main() {
// Allocate an integer on the heap
let _box2 = Box::new(5i32);
// A nested scope:
{
// Allocate an integer on the heap
let _box3 = Box::new(4i32);
// `_box3` is destroyed here, and memory gets freed
}
// Creating lots of boxes just for fun
// There's no need to manually free memory!
for _ in 0u32..1_000 {
create_box();
}
// `_box2` is destroyed here, and memory gets freed
}
Звісно, ми можемо додатково перевірити наявність помилок пам’яті, використовуючи valgrind:
$ rustc raii.rs && valgrind ./raii
==26873== Memcheck, a memory error detector
==26873== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==26873== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==26873== Command: ./raii
==26873==
==26873==
==26873== HEAP SUMMARY:
==26873== in use at exit: 0 bytes in 0 blocks
==26873== total heap usage: 1,013 allocs, 1,013 frees, 8,696 bytes allocated
==26873==
==26873== All heap blocks were freed -- no leaks are possible
==26873==
==26873== For counts of detected and suppressed errors, rerun with: -v
==26873== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Жодних витоків тут немає!
Деструктор
Поняття деструктора в Rust надається через трейт Drop. Деструктор
викликається, коли ресурс виходить із області видимості. Цей трейт не
обов’язково реалізовувати для кожного типу; реалізуйте його для свого типу лише якщо
вам потрібна власна логіка деструктора.
Запустіть приклад нижче, щоб побачити, як працює трейт Drop. Коли змінна в
функції main виходить із області видимості, буде викликано користувацький деструктор.
struct ToDrop;
impl Drop for ToDrop {
fn drop(&mut self) {
println!("ToDrop is being dropped");
}
}
fn main() {
let x = ToDrop;
println!("Made a ToDrop!");
}