Rustの変数の束縛と所有権メモ
他の言語との比較
Python
Pythonでは型によって値がミュータブルか決まっている
イミュータブル型は新しいオブジェクトが生成されるためコピーに近い挙動になる
リストはミュータブルとして決められているため、代入では同じオブジェクトを指すため、片方の変更がもう片方に影響する
束縛で考えると、xというラベルの貼られていたリストにyというラベルが貼られる
C
Cにおける代入は値のコピーで、新たな変数に割り当てられたメモリ領域に値が入る
コンパイラは左辺値のオフセットに右辺の値を設定している(ローカル変数の場合)、これをコピーと考える
Rust
コピーセマンティクス
aをCopyトレイトを実装した型とする
let b = a;としたとき、bのメモリ領域が確保され、aの値がコピーされる
Cの代入と同じ
ムーブセマンティクス
code:rs
let a = String::from("hoge");
let b = a;
String型はCopyトレイトを実装していないため、所有権がaからbにムーブしている
束縛で考えると、メモリ上の値にaというラベルを貼っていたが、ムーブによってaは剥がされbが新たに貼られる
関数が所有権を消費することの意味
関数の中の変数に所有権が移動することを「所有権を消費する」と言う
関数内に移動した所有権のライフタイムは関数スコープになるため、関数を抜けると渡した値はメモリから解放される
値を関数の引数に渡した後に使用しない場合、メモリの節約になる
リファレンス(参照)
イミュータブルなリファレンスは複数作成できる
ミュータブルなリファレンス
まず元の変数がミュータブルで宣言されている必要がある
リファレンスのスコープに1つしか作ることができない
リファレンスのスコープ
リファレンスのスコープは、そのリファレンスが最後に使われたところで終わる
複数のミュータブルなリファレンスはスコープが重ならなければ問題ない
リファレンスのスコープ内
元の変数の値を変更することは不可
ミュータブルなリファレンスのスコープ内では
元の変数を使用する(読む)ことも不可
借用している間は元の変数の値を利用できない、と考える
意図しない値の変更を防ぐため
shared XOR mutable
シャドーイング
code:rs
let x = 1;
let x = 2;
すでにxを宣言していても、新たな値にxという名前を束縛することができる
これは新しいxのスコープでは、既存のxを隠しているような挙動になる
code:rs
let x = 1;
{
let x = 2;
println!("{}", x); // 2
}
println!("{}", x); // 1