導入
所有権は、たった3つのルールに集約されます。まずこの3つを丸ごと頭に入れてしまいましょう。以降のレッスンは、すべてこの3ルールの具体例です。
説明
Rust の所有権の3ルールは次のとおりです。
「スコープ」とは、変数が有効な範囲——ふつうは { } で囲まれた区間です。
fn main() {
// ここではまだ s は存在しない
let s = String::from("hello"); // s が誕生。ヒープに "hello" を確保し、s がその所有者に
println!("{s}"); // s は有効。使える
} // ← ここで s のスコープが終わる。ルール3により s が drop され、ヒープが自動解放
let s = String::from("hello");の瞬間、ヒープ上の"hello"の所有者はs(ルール1・2)。mainの}に来るとsはスコープを抜け、Rust が自動でdrop(解放処理)を挿入します(ルール3)。C言語で言えばfree(s)を、Rust があなたの代わりに正しい位置に書いてくれるイメージです。
graph TD
a["let s = String::from(...)<br/>s がヒープの所有者になる"] --> b["s を使う"]
b --> c["スコープの } に到達"]
c --> d["Rust が自動で drop(s) を挿入<br/>ヒープを解放"]
このルールがあるおかげで、解放し忘れ(誰かが必ず所有者で、スコープ終わりに解放される)も、二重解放(所有者は1人だけなので2回解放されない)も、原理的に起きません。しかも判断はコンパイル時。実行時のGCは不要です。
問題は「所有者は1人だけ」というルール2です。では、String を別の変数に代入したり、関数に渡したりすると、所有権はどうなるのでしょう? それが次のレッスンの「ムーブ」です。
試すには
3ルールを声に出して覚えてしまいましょう。「①値には所有者が1人 ②同時に1人だけ ③所有者がスコープを抜けたら破棄」。この3行が、これから出てくるあらゆる「借用」「ライフタイム」の土台になります。