前回はRustに「所有権」という概念があることを学んだ。もう少し一般化した規則を学んでいこう。
Rustでは変数の値の所有権が移動(ムーブ)する。ムーブ後、どこかのタイミングで値の生存期間が終わるとそこで値は解放され、以降の処理では一切アクセスできなくなる。
ムーブは次の個所で発生する。
- パターンマッチ(match式だけでなく変数の束縛も含む)
- 関数呼び出し
- 関数やブロックからのリターン
- コンストラクター(構造体やenumの作成時に使用するもの)
- クロージャーのmoveキーワード
ムーブした後は元の変数では値を使ったり参照したりすることはできない。解放されているからだ。
Rustではムーブを利用することを「ムーブセマンティクス」と呼ぶ。
所有権の移動について、簡潔な例で確認しておこう。次のコードでは、変数「s」「t」「u」の順に値を束縛し、意図的に所有権を移動させている。
fn main() {
// s に「text」という文字列の値を束縛
let s = String::from("text");
// tにsの値を束縛
// この時点でsは値が解放済みになる
let t = s;
// uにtの値を束縛
// この時点でtは値が解放済みになる
let u = t;
// これらは解放済みなのでコメントアウトするとコンパイルエラー
// println!("{}", s);
// println!("{}", t);
// これはOK
println!("{}", u);
}
これを模式図にしてみると、次のような動きになっている。
まず、変数sに値を束縛すると、その値に対する所有権が生まれる。
次に変数tにsの値を束縛する。すると、sが持っていた「text」の所有権がtに移る。
最後に変数uにtの値を束縛すると、今度は所有権がuに移動する。