所有権とムーブ
変数には自身の保持する資源を開放する責任があるため、資源は一度に一つの所有者 しか持つことができません。これはまた、資源を2度以上開放することができないということでもあります。ここで、全ての変数が資源を所有するわけではないということに注意しましょう。(e.g. 参照)
変数を代入する(let x = y
)際や、関数に引数を値渡しする(foo(x)
)際は、資源の 所有権 が移動します。Rustっぽく言うと、「 ムーブ 」です。
資源を移動すると、それまでの所有者(訳注:変数などのこと)を使用することはできなくなります。これによりダングリングポインタの発生を防げます。
// この関数はヒープメモリ上の資源の所有権を取ります。 fn destroy_box(c: Box<i32>) { println!("Destroying a box that contains {}", c); // `c`は破棄されメモリは開放されます。 } fn main() { // _スタック_上に置かれた整数 let x = 5u32; // `x`を`y`に *コピー* します。元の値が移動するわけではありません。 let y = x; // 両方の値はそれぞれ独立に使うことができます。 println!("x is {}, and y is {}", x, y); // `a`は_ヒープ_上の整数へのポインタ。 let a = Box::new(5i32); println!("a contains: {}", a); // `a`を`b`に *ムーブ* します。 let b = a; // すなわち、`a`の指すメモリ上の番地が`b`にコピーされるため // いずれもヒープ上の同じ値を指すポインタとなります。 // しかし所有権は`b`にあります。 // エラー!`a`は所有権を持たないため、ヒープ上のデータにアクセスできません。 //println!("a contains: {}", a); // TODO ^ 試しにここをアンコメントしてみましょう。 // この関数はヒープメモリ上の所有権を`b`から取ります。 destroy_box(b); // この時点でヒープメモリ上の資源は開放されているので、次の操作は // 解放済みメモリをデリファレンスすることになります。 // しかしそれはコンパイラが許しません。 // エラー!上述の理由より //println!("b contains: {}", b); // TODO ^ 試しにここをアンコメントしてみましょう。 }