RAII
Rustの変数は単にデータをスタック上に保持するだけのものではありません。例えばヒープメモリを確保するBox<T>のように、変数はメモリ上の資源を 保有 する場合もあるのです。RustはRAII(Resource Acquisition Is Initialization)を強制するので、オブジェクトがスコープを抜けると、必ずデストラクタが呼び出されてそのオブジェクトが保持していた資源が解放されます。
この振る舞いは リソースリーク バグを防ぐのに役立ちます。手動でメモリを解放したり、メモリリークバグにわずらわされたりすることはなくなるのです!簡単な例で説明しましょう。
// raii.rs
fn create_box() {
// 整数をヒープ上に確保。
let _box1 = Box::new(3i32);
// `_box1`はここで破棄され、メモリは解放されます。
}
fn main() {
// 整数をヒープ上に確保。
let _box2 = Box::new(5i32);
// ネストしたスコープ
{
// 整数をヒープ上に確保。
let _box3 = Box::new(4i32);
// `_box3`はここで破棄され、メモリは解放されます。
}
// お遊びで大量のボックスを作ります。
// もちろん手動で開放する必要はないよ!
for _ in 0u32..1_000 {
create_box();
}
// `_box2`はここで破棄され、メモリは解放されます。
}
valgrindを用いて、メモリエラーが起きていないか2重チェックすることももちろん可能です。
$ 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トレイトは型定義のたびに必ず実装する必要があるわけではなく、デストラクタに独自のロジックが必要な場合にのみ実装します。
下のコードを実行して、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!");
}