第1章: Rustの歴史と設計思想
学習目標
- Rustが生まれた歴史的背景を理解する
- Rustの設計思想とトレードオフを学ぶ
- Rustが解決しようとした問題を知る
- 他の言語との比較から、Rustの立ち位置を把握する
---
1.1 プログラミング言語史におけるRustの誕生
1.1.1 システムプログラミングの課題
システムプログラミングの世界は、長年にわたり2つの陣営に分かれていました:
┌─────────────────────────────────────────────────────────┐
│ システムプログラミングの二極化 │
├─────────────────────────────────────────────────────────┤
│ │
│ 【C/C++陣営】 【高水準言語陣営】 │
│ │
│ ✓ 高速 ✓ メモリ安全 │
│ ✓ ハードウェア制御 ✓ 生産性が高い │
│ ✗ メモリ安全性なし ✗ パフォーマンスが低い │
│ ✗ データ競合の危険 ✗ GCによるレイテンシ │
│ │
│ 「速いが危険」 vs 「安全だが遅い」 │
│ │
└─────────────────────────────────────────────────────────┘
この二極化は、長年にわたりfalse dichotomy(誤った二分法)として受け入れられてきました。
1.1.2 Mozillaの問題:Firefoxとセキュリティ
2006年、Mozilla Foundationは深刻な問題に直面していました:
統計データ(2006-2010):
- Firefoxのセキュリティバグの 70%以上 がメモリ安全性の問題
- Use-after-free、バッファオーバーフロー、NULL pointer dereference
- これらはすべて C++の手動メモリ管理 に起因
Firefox Security Bugs (2006-2010)
────────────────────────────────────
Memory Safety: ████████████████████████ 70%
Logic Errors: ████████ 20%
Other: ███ 10%
Graydon Hoareの洞察(Rust作者、当時Mozilla Research):
> 「私たちはC++でブラウザを書いている。C++は高速だが、メモリ安全性がない。 > このトレードオフは本当に必要なのか?理論的には、コンパイル時に安全性を保証できるはずだ。」
1.1.3 Rustプロジェクトの開始(2006-2015)
タイムライン:
2006 Graydon Hoare、個人プロジェクトとしてRustを開始
│ OCaml実装、実験的な型システム
│
2009 Mozillaが公式にスポンサー
│ プロトタイプから本格的な言語開発へ
│
2010 初めて公開発表
│ コンパイラをOCamlからRustへ self-hosting
│
2012 Rust 0.1リリース
│ 所有権システムの基礎を導入
│
2015 Rust 1.0リリース - 安定版
│ 後方互換性の保証開始
│
2018 Rust 2018 Edition
│ エルゴノミクス改善、async/await導入準備
│
2021 Rust 2021 Edition
│ async/await安定化、エラー処理改善
│
2024 Rust Foundation設立後の成長期
│ 産業界での広範な採用
---
1.2 Rustの設計思想:ゼロコスト抽象化
1.2.1 コアとなる設計原則
Rustは3つの柱の上に構築されています:
┌─────────────────────────────────────────────────────────┐
│ Rustの3つの柱 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐│
│ │ │ │ │ │ ││
│ │ Memory │ │ Zero │ │Concurrent ││
│ │ Safety │◄────►│ Cost │◄────►│ Safety ││
│ │ │ │Abstraction │ │ ││
│ └────────────┘ └────────────┘ └────────────┘│
│ │
│ 「安全」 「パフォーマンス」 「並行性」 │
│ │
└─────────────────────────────────────────────────────────┘
1. メモリ安全性(Memory Safety)
C++の問題:
// C++: コンパイルは通るが、実行時にクラッシュ
std::vector<int> vec = {1, 2, 3};
int* ptr = &vec[0];
vec.push_back(4); // vecが再割り当てされるかも
std::cout << *ptr; // Use-after-free! 未定義動作
Rustの解決策:
// Rust: コンパイル時にエラー
let mut vec = vec![1, 2, 3];
let ptr = &vec[0];
vec.push(4); // コンパイルエラー!
// "cannot borrow `vec` as mutable
// because it is also borrowed as immutable"
println!("{}", ptr);
なぜコンパイル時にエラーにできるのか?
Rustは所有権システム(Ownership System)を採用しています:
- すべての値には1つの所有者が存在
- 所有者がスコープを抜けると、値は自動的に解放
- 借用(borrow)には厳格なルールがある
これにより、コンパイル時に以下を保証:
- Use-after-free なし
- Double-free なし
- NULL pointer dereference なし
- データ競合なし
2. ゼロコスト抽象化(Zero-Cost Abstraction)
Bjarne Stroustrup(C++の父)の原則:
> 「使わない機能にはコストを払わない。使う機能は手書き以上に効率化できない。」
Rustはこの原則を型システムで実現:
// 高水準な抽象化
let sum: i32 = vec![1, 2, 3, 4, 5]
.iter()
.filter(|&x| x % 2 == 0)
.map(|x| x * 2)
.sum();
// コンパイル後は手書きループと同等の機械語に!
// 実行時オーバーヘッドなし
コンパイル後(最適化されたアセンブリ):
; シンプルなループと加算命令のみ
; イテレータのオーバーヘッドは完全に消える
mov eax, 12 ; 結果を直接計算
ret
3. 並行安全性(Concurrency without Data Races)
従来の言語の問題:
// C言語: コンパイルは通るが、データ競合
int counter = 0;
void* thread_func(void* arg) {
for (int i = 0; i < 100000; i++) {
counter++; // データ競合!
}
return NULL;
}
Rustの解決策:
// Rust: データ競合はコンパイル時にエラー
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
型システムによる保証:
Arc: スレッド間で安全に共有可能(参照カウント)Mutex: 排他制御を強制Send/Syncトレイト: スレッド安全性を型で表現
---
1.3 Rustが解決した問題とトレードオフ
1.3.1 解決した問題
1. メモリ安全性とパフォーマンスの両立
従来:
- C/C++: 高速だが、脆弱性の温床
- Java/Python: 安全だが、GCによるレイテンシ
Rustの解決:
- コンパイル時にメモリ安全性を保証
- 実行時オーバーヘッドなし(GC不要)
2. データ競合の撲滅
┌─────────────────────────────────────────────────────────┐
│ 並行プログラミングの安全性スペクトラム │
├─────────────────────────────────────────────────────────┤
│ │
│ C/C++ Java/Go Rust │
│ ─────── ─────── ───── │
│ 全て手動 ランタイム コンパイル時 │
│ ミスし放題 チェック 型チェック │
│ │
│ 速い ◄─────────────────────────────────► 安全 │
│ Rustはこの両端を達成 │
│ │
└─────────────────────────────────────────────────────────┘
3. Null参照の問題
Tony Hoare(Null参照の発明者)の謝罪:
> 「I call it my billion-dollar mistake.」 > (これは私の10億ドルの過ちだ)
Rustの解決:
// Rust: Nullは存在しない。代わりにOption<T>
fn find_user(id: u32) -> Option<User> {
// ...
}
match find_user(42) {
Some(user) => println!("Found: {}", user.name),
None => println!("Not found"),
}
// コンパイラがNoneケースの処理を強制
1.3.2 トレードオフと学習曲線
Rustの代償:
┌─────────────────────────────────────────────────────────┐
│ 学習曲線の比較 │
├─────────────────────────────────────────────────────────┤
│ │
│ 難しさ │
│ ▲ │
│ │ ╱ Rust │
│ │ ╱╱╱╱ │
│ │ ╱╱╱╱ │
│ │ ╱╱╱╱ │
│ │ ╱╱╱╱ C++ │
│ │ ╱╱╱╱ ╱ Python/Go │
│ │╱╱╱╱╱╱╱╱ │
│ └────────────────────────────────────► 時間 │
│ │
│ Rust: 初期は急勾配だが、プラトーに達すると生産性向上 │
└─────────────────────────────────────────────────────────┘
学習の障壁:
- 所有権システム:従来の言語にない概念
- ライフタイム注釈:明示的なメモリ寿命の管理
// 初心者が恐れるコード
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
- エラーハンドリング:Result型の強制
if err != nil よりも厳格
- ? 演算子の理解が必要しかし、これらは投資に値する:
> 「If it compiles, it usually works.」 > (コンパイルが通れば、大抵動く)
- コンパイル時に多くのバグを捕捉
- リファクタリングが安全
- 並行プログラミングが怖くない
---
1.4 Rustと他の言語の比較
1.4.1 性能比較(Computer Language Benchmarks Game)
実行時間(正規化)
─────────────────
C (gcc) 1.0x ████
Rust 1.03x ████
C++ (g++) 1.12x █████
Go 2.83x ████████████
Java (OpenJDK) 1.89x ████████
Python (CPython) 71.9x ███████████████████████████████████████
メモリ使用量(正規化)
─────────────────
C 1.0x ███
Rust 1.08x ███
C++ 1.34x ████
Go 3.70x ███████████
Java 6.20x ██████████████████
Python 9.64x █████████████████████████████
Rustの強み:
- C/C++と同等の性能
- メモリ使用量も最小クラス
- GC言語よりも予測可能なレイテンシ
1.4.2 言語パラダイム比較
| 特性 | C | C++ | Rust | Go | Java |
|---|---|---|---|---|---|
| メモリ安全性 | ✗ | ✗ | ✓ | ✓ | ✓ |
| GC不要 | ✓ | ✓ | ✓ | ✗ | ✗ |
| ゼロコスト抽象化 | ✗ | ✓ | ✓ | ✗ | ✗ |
| 並行安全性(型) | ✗ | ✗ | ✓ | 部分的 | 部分的 |
| パターンマッチング | ✗ | 限定的 | ✓ | ✗ | 限定的 |
| トレイト/インターフェース | ✗ | ✓ | ✓ | ✓ | ✓ |
| マクロシステム | ✓ | ✓ | ✓ | ✗ | ✗ |
| 学習曲線 | 中 | 高 | 高 | 低 | 中 |
1.4.3 ユースケース別の選択
Rust が最適:
- システムプログラミング(OS、ドライバ)
- 組み込みシステム
- Webサーバー(高負荷)
- ゲームエンジン
- ブロックチェーン
- CLI ツール
C/C++ が依然として優位:
- 既存のエコシステム(Linux kernel)
- リアルタイムシステム(RustのLLVMが未対応な場合)
- ハードウェア固有の最適化が必要な場合
Go が優位:
- マイクロサービス(高速開発)
- ネットワークサーバー(GCの影響が小さい)
- 社内ツール(学習コストの低さ)
---
1.5 Rustのエコシステムと産業界での採用
1.5.1 主要な採用事例
1. Mozilla(原点)
- Firefox: Servo(新しいレンダリングエンジン)の成果を統合
- Stylo: CSS エンジンをRustで再実装(4xの高速化)
2. Microsoft
- Windows の一部コンポーネントをRustで再実装
- Azure IoT Edge のセキュリティクリティカルな部分
3. AWS(Amazon Web Services)
- Firecracker: Lambda と Fargate のマイクロVM
- Bottlerocket: コンテナ専用OS
- s2n-quic: QUICプロトコル実装
4. Google
- Android の Bluetooth スタック
- Fuchsia OS のコアコンポーネント
5. Meta(Facebook)
- Mononoke: Mercurial のサーバー
- Diem(旧Libra)ブロックチェーン
6. Cloudflare
- エッジコンピューティングプラットフォーム
- DDoS対策システム
1.5.2 統計データ(2024年)
Stack Overflow Developer Survey:
- 最も愛されている言語: 8年連続1位
- 87.6% の開発者が「また使いたい」と回答
GitHub:
- スター数トップ10のプロジェクトにRustが多数
- 年々増加する新規プロジェクト
Crate.io(Rustのパッケージレジストリ):
- 150,000+ クレート(パッケージ)
- 毎日数百の新規クレート
---
1.6 Rustの哲学:Fearless Concurrency
1.6.1 "Fearless"の意味
Rustのスローガン:"Fearless Concurrency"(恐れなき並行性)
┌─────────────────────────────────────────────────────────┐
│ 従来の並行プログラミング vs Rust │
├─────────────────────────────────────────────────────────┤
│ │
│ 【従来】 【Rust】 │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ コードを書く │ │ コードを書く │ │
│ └───────┬──────┘ └───────┬──────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ コンパイル │ │ コンパイル │ │
│ └───────┬──────┘ └───────┬──────┘ │
│ │ │ │
│ ▼ │ │
│ ┌──────────────┐ │ │
│ │ 実行 │ │ │
│ └───────┬──────┘ │ │
│ │ │ │
│ ▼ │ │
│ ┌──────────────┐ │ │
│ │ データ競合! │ エラーはここで捕捉! │
│ │ デバッグ地獄 │ │ │
│ └───────┬──────┘ ▼ │
│ │ ┌──────────────┐ │
│ │ │ 安全に実行 │ │
│ │ └──────────────┘ │
│ │ │
│ └───► 「実行時」 「コンパイル時」 │
│ │
└─────────────────────────────────────────────────────────┘
1.6.2 Rustの約束
Rustがコンパイル時に保証すること:
- スレッド安全性
Send / Sync トレイトによる型レベルの保証- 型安全性
しかし、Rustが保証しないこと:
- 論理エラー:アルゴリズムの間違い
- リソースリーク:メモリ以外(ファイルハンドル等)
- デッドロック:型システムでは防げない
---
1.7 まとめ:なぜRustを学ぶのか?
1.7.1 Rustを学ぶべき理由
1. 未来の標準になる可能性
- Linux kernel が Rust をサポート(6.1以降)
- NIST(米国標準技術研究所)がメモリ安全言語を推奨
2. キャリアの価値
- 需要が高い(求人数増加)
- 高給与(Stack Overflow調査)
3. より良いプログラマになる
- メモリ管理の深い理解
- 並行処理の正しい考え方
- 型システムの力
4. 楽しい
- コンパイラが親切(エラーメッセージが詳細)
- エコシステムが充実(Cargo、Crates.io)
- コミュニティが温かい
1.7.2 学習のロードマップ
┌─────────────────────────────────────────────────────────┐
│ Rust学習の推奨パス(3ヶ月) │
├─────────────────────────────────────────────────────────┤
│ │
│ Week 1-2: 基本構文(変数、関数、制御構文) │
│ ├─ 「The Book」Chapter 1-4 │
│ └─ Rustlings 演習 │
│ │
│ Week 3-4: 所有権システム(山場!) │
│ ├─ 「The Book」Chapter 4 │
│ ├─ 所有権の可視化演習 │
│ └─ 借用チェッカーとの戦い │
│ │
│ Week 5-6: 構造体、Enum、パターンマッチング │
│ ├─ 「The Book」Chapter 5-6 │
│ └─ 小さなCLIツール作成 │
│ │
│ Week 7-8: エラー処理、ジェネリクス、トレイト │
│ ├─ 「The Book」Chapter 9-10 │
│ └─ 実用的なライブラリ設計 │
│ │
│ Week 9-10: モジュール、テスト、Cargo │
│ └─ 実際のプロジェクトを開始 │
│ │
│ Week 11-12: 並行処理、スマートポインタ │
│ └─ 非同期プログラミング入門 │
│ │
└─────────────────────────────────────────────────────────┘
1.7.3 次のステップ
次の章では、Rustの環境構築とCargoツールチェーンを学びます。実際にRustプログラムを書く準備を整えましょう。
心構え:
- 借用チェッカーとの戦いは誰もが通る道
- エラーメッセージをよく読む(驚くほど親切)
- コミュニティに質問する(Rust Users Forum、Discord)
---
参考資料
公式ドキュメント
- The Rust Programming Language(通称「The Book」)
- Rust By Example
- Rustlings(インタラクティブ演習)