rust-ownership - 背景

歴史的経緯

メモリ安全性の課題

  • C言語時代(1972年〜)
- 手動メモリ管理 - ダングリングポインタ、バッファオーバーフロー - セキュリティ脆弱性の温床

  • ガベージコレクション(1959年〜)
- Lisp で初導入 - Java, Go, Python などで採用 - 実行時オーバーヘッド

  • RAII(1984年〜)
- C++ で確立 - リソースの自動解放 - 例外安全性の向上

  • Rust所有権(2010年〜)
- コンパイル時メモリ安全性 - ゼロコストの抽象化 - データ競合の防止

所有権システムの設計

Rust の設計原則:
1. 各値には所有者が1つだけ存在する
2. 所有者がスコープを抜けると値は破棄される
3. 所有権は移動するか、借用される

コンピュータサイエンス的な意味

線形型システム

所有権は線形型(Linear Types)に基づく:

// 線形型: 値は正確に1回使用される
let x = String::from("hello");
let y = x;  // x から y へ所有権が移動
// x は使用不可(線形性の保証)

アフィン型システム

Rustはアフィン型(Affine Types)を採用:

// アフィン型: 値は最大1回使用される(0回も可)
let x = String::from("hello");
drop(x);  // 明示的に破棄(0回使用)

借用チェッカーの仕組み

借用規則:
1. &T(不変借用): 複数同時に存在可能
2. &mut T(可変借用): 同時に1つのみ
3. &T と &mut T は同時に存在不可

これにより:
- データ競合がコンパイル時に検出
- 読み取り中の書き込みを防止

ライフタイムと領域解析

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

// 'a は x と y の共通の最小ライフタイム
// 戻り値は 'a の間有効

実践での活用

ゼロコピーパーサー

struct Parser<'a> {
    input: &'a str,
    position: usize,
}

impl<'a> Parser<'a> {
    // 入力をコピーせずに解析
    fn parse_token(&mut self) -> &'a str {
        let start = self.position;
        // ...
        &self.input[start..self.position]
    }
}

効率的なビルダーパターン

struct StringBuilder {
    buffer: String,
}

impl StringBuilder {
    fn append(mut self, s: &str) -> Self {
        self.buffer.push_str(s);
        self  // 所有権を返す
    }

    fn build(self) -> String {
        self.buffer  // 所有権を移動
    }
}

実世界とのギャップ

他言語との比較

言語 メモリ管理 安全性 性能
C 手動
C++ RAII + 手動
Java GC
Go GC
Rust 所有権

学習曲線の考慮

初期の壁:
- 借用チェッカーとの戦い
- ライフタイムの理解
- "Fighting the borrow checker"

克服後:
- バグの少ないコード
- リファクタリングの安心感
- パフォーマンスの予測可能性

現実世界での制約

// 時として unsafe が必要
// 例: FFI、自己参照構造体

unsafe {
    // コンパイラが検証できない操作
    // 人間が安全性を保証
}