導入
第3章から続いたメモリの旅も、ここで一区切りです。スタックとヒープ、所有権、借用、ライフタイム——バラバラに見えた概念は、実は「GC なしでメモリを安全に管理する」という1つの目的でつながった、ひとつのシステムでした。全体像を1枚に束ねましょう。
説明
Rust のメモリ管理を、1本の物語として振り返ります。
- スタックとヒープ(第3章):固定サイズの値はスタックに、可変・実行時サイズのデータはヒープに置かれる。ヒープの「いつ解放するか」問題を解くのが所有権。
- 所有権(第4章):ヒープデータには所有者が1人。所有者がスコープを抜けたら自動で解放(
drop)。代入・関数渡しで所有権はムーブ(元は無効化)。複製したいなら明示的にclone()。→ 解放忘れ・二重解放が起きない。 - 借用(第5章):
&で所有権を渡さず貸す。不変参照&Tは何個でも、可変参照&mut Tは同時に1つだけで他の参照を排除。→ データ競合が起きない。 - ライフタイム(第6章):すべての参照は、指す先のデータが生きている期間を超えて使えない。コンパイラが追跡し、ふつうは自動推論、曖昧なときだけ
'aで注釈。→ ダングリング参照が起きない。
これらをまとめると、次の相関図になります。
graph TD
goal["目標:GC なしで<br/>メモリ安全 かつ 高速"]
goal --> own["所有権<br/>解放忘れ・二重解放を防ぐ"]
goal --> bor["借用 &T / &mut T<br/>データ競合を防ぐ"]
goal --> life["ライフタイム<br/>ダングリング参照を防ぐ"]
own --> compile["すべてコンパイル時に検査<br/>実行時コストゼロ"]
bor --> compile
life --> compile
ここで強調したいのは、これらのチェックはすべてコンパイル時に終わることです。プログラムが動いている間、所有権や借用を監視する処理は一切走りません。GC のような一時停止もありません。「借用チェッカーとの戦い」を一度くぐり抜けてコンパイルが通れば、そのバイナリはメモリ安全が保証された状態で、C並みの速度で動きます。これが Rust の約束です。
最初は借用チェッカーに何度も叱られるでしょう。それは「あなたのコードにメモリの危険がある」とコンパイラが先回りして教えてくれているということ。実行時にクラッシュやセキュリティ事故として現れる前に、机の上で潰せるのです。慣れると、この厳しさは頼もしさに変わります。
次章からは、この土台の上に struct・enum・トレイト・スマートポインタ といった、実際にプログラムを組み立てる道具を載せていきます。所有権の感覚を持ったまま読み進めれば、なぜそれらがそういう設計になっているのかが自然に見えてくるはずです。
試すには
ここまでの第3〜6章をもう一度ざっと読み返し、「所有権・借用・ライフタイムが、それぞれどのメモリバグを防いでいるか」を自分の言葉で言えるか確かめてみてください。①所有権=解放忘れ/二重解放、②借用=データ競合、③ライフタイム=ダングリング参照。この対応が言えれば、Rust の心臓部はあなたのものです。