CATHODE COASTaccess to tools
1 min read

Rustの所有権を、夜が明けるまでに理解する

所有権・借用・ライフタイムを、最短距離で。コンパイラと喧嘩する夜を終わらせるための地図。


所有権(ownership)は、Rust が「GC なしでメモリ安全」を実現するための背骨だ。 最初はコンパイラと喧嘩しているように感じるが、ルールは驚くほど少ない。 夜が明けるまでに、その地図を描いてしまおう。

所有権の三つのルール

Rust の所有権は、たった三つの規則に集約される。

  1. 各値には、それを所有する変数(owner)がただ一つだけ存在する。
  2. owner はある時点でただ一つ。
  3. owner がスコープを抜けると、値は drop される。

ムーブ(move)

値を別の変数に代入すると、所有権は移動する。元の変数はもう使えない。

move.rs
fn main() {
    let s1 = String::from("inherent vice");
    let s2 = s1;            // 所有権が s1 -> s2 へムーブ
 
    // println!("{s1}");    // ← コンパイルエラー: value borrowed after move
    println!("{s2}");       // OK
}

String はヒープ上のバッファを持つため、コピーではなくムーブになる。 二重解放(double free)をコンパイル時に潰すための設計だ。

借用(borrow)

所有権を渡さずに値へアクセスしたいときは、参照を借りる

borrow.rs
fn length(s: &String) -> usize {
    s.len()
}
 
fn main() {
    let s = String::from("turn on, tune in");
    let n = length(&s);    // 不変借用。所有権は s に残る
    println!("{s}{n} バイト");
}

借用には二つの規則がある。

  • 任意の時点で、不変参照は何個でも OR 可変参照はちょうど一つ
  • 参照は、参照先より長生きしてはいけない(ライフタイム)。

この「共有 xor 可変」こそが、データ競合をコンパイル時に排除する核心だ。

まとめ

所有権は制約ではなく、メモリ安全の証明をコンパイラに肩代わりさせる契約だ。 借用チェッカーと喧嘩した夜の数だけ、ランタイムのクラッシュが消えていく。