Rust入門シリーズの第5回です。所有権はRustを最も特徴づける考え方であり、ガベージコレクタなしでメモリ安全になる理由です。
ルール#
- Rustの各値には1つの所有者がいる。
- 同時に所有者は1つだけ。
- 所有者がスコープを外れると値はドロップされる。
fn main() {
let s = String::from("hello");
println!("{s}");
} // sがスコープを外れる; メモリが解放されるrustムーブセマンティクス#
値を別の変数に代入すると所有権が移動し、古い束縛は使えなくなります:
let s1 = String::from("hello");
let s2 = s1;
// println!("{s1}"); // エラー: 値が移動した
println!("{s2}"); // 成功rust文字列はコピーされません。データと所有権がs2に移動します。だからRustには解放後使用(use-after-free)バグがありません。
Copy型#
コピーが安価な小さな型は、移動ではなくコピーされます。これらはCopyトレイトを実装しています:
let a = 5;
let b = a; // aは引き続き使用可能rust整数、浮動小数点数、ブール、charはCopyです。StringとVecは違います。
Clone#
ヒープに割り当てられた値をコピーするには、明示的に.clone()を呼びます:
let s1 = String::from("hello");
let s2 = s1.clone();
println!("{s1} {s2}"); // 両方有効rustcloneはディープコピーを作ります。明示的な呼び出しでコストが見えます。
所有権と関数#
値を関数に渡すと移動し、返すとまた移動します:
fn take_and_return(s: String) -> String {
s
}
fn main() {
let s = String::from("hi");
let s = take_and_return(s); // 移動され、また返される
}rust所有権とスコープ#
値は所有者のスコープが終わるとドロップされます。スコープベースのクリーンアップにより、メモリだけでなくリソースも自動的に解放されます。
なぜ重要か#
所有権により、コンパイラは解放後使用・二重解放・ダングリングポインタが存在しないことを証明できます — CやC++を悩ませるバグです。普通のコードを書くだけで、コンパイラが安全性を強制します。
結論#
所有権: 値ごとに1人の所有者、デフォルトでムーブ、Copy型はコピー、深いコピーには明示的なclone。シリーズ次回は参照とスライスです。