Rustの言語設計・基礎文法
作成日:
Rust programming-language systems-programming
概要
RustはGCを持たずにメモリ安全を保証する言語。コンパイラがメモリの所有・借用・寿命をチェックすることで、C++と同等の実行速度を保ちながら、メモリ安全性を静的に保証する。
基本概念
所有権(Ownership)
- 変数は「所有者」を1つだけ持つ
- スコープを抜けると自動的にメモリが解放される(
drop) - 所有権の移動(ムーブセマンティクス)により、二重解放を構造的に防止する
let s1 = String::from("hello");
let s2 = s1; // s1 の所有権が s2 に移動
// println!("{}", s1); // コンパイルエラー: s1 は使えない
println!("{}", s2); // OK
借用と参照(Borrowing & References)
- 不変参照(
&T)は同時に複数持てる - 可変参照(
&mut T)は同時に1つだけ - この規則によりデータ競合をコンパイル時に排除する
let s = String::from("hello");
let r1 = &s; // 不変参照
let r2 = &s; // 不変参照(同時に複数OK)
println!("{} and {}", r1, r2);
// let r3 = &mut s; // コンパイルエラー: 不変参照が存在する間、可変参照は取れない
ライフタイム(Lifetimes)
- 参照の有効期間をコンパイラに明示するアノテーション(
'aなど) - ダングリングポインタ(解放済みメモリを指す参照)をコンパイルエラーで防ぐ
- 多くのケースで省略(elision)が可能だが、複雑な関数シグネチャでは明示が必要
// ライフタイム注釈を明示する例
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
エラー型:Result / Option
nullを型システムから排除Option<T>: 値があるかもしれない(Some(T)/None)Result<T, E>: 成功か失敗か(Ok(T)/Err(E))- エラーを戻り値で表現することで、エラーの伝播が型で追跡できる
fn divide(a: f64, b: f64) -> Option<f64> {
if b == 0.0 { None } else { Some(a / b) }
}
fn read_file(path: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(path)
}
デフォルト不変(Immutability by Default)
- 変数はデフォルトで不変
- 可変にする場合は
mutを明示する - コードの意図を明確化し、意図しない変更を防ぐ
let x = 5;
// x = 6; // コンパイルエラー
let mut y = 5;
y = 6; // OK
トレイト(Traits)
- 継承ではなくコンポジションで多態性を実現
- インターフェースに近い概念だが、デフォルト実装・型制約(トレイト境界)も持つ
trait Greet {
fn hello(&self) -> String;
fn greet(&self) { println!("{}", self.hello()); } // デフォルト実装
}
struct Person { name: String }
impl Greet for Person {
fn hello(&self) -> String {
format!("Hello, {}!", self.name)
}
}
ダングリングポインタとは
解放済みのメモリを指し続けているポインタのこと。
- 原因: ポインタが「実体とは独立して場所だけを持てる」ため、実体が解放された後も参照を保持できてしまう
- 読むとゴミ値を返す、書くと別の変数を破壊する可能性がある
- 「たまたま動く」ケースが最も危険(テストは通るが本番でクラッシュ)
- Rustではこのケースをコンパイルエラーとして検出する
メモリ管理方式の比較
| 方式 | C++ | Java / Python | Rust |
|---|---|---|---|
| メモリ管理 | 手動 | GCが自動 | 所有権(コンパイル時) |
| ダングリング | 起きうる | 起きない | コンパイルエラー |
| 実行時コスト | 低い | GCのオーバーヘッドあり | 低い(C++同等) |
| 安全性 | 開発者次第 | 高い | 高い |
GCのデメリット
- Stop the World: GC実行中に処理が止まる
- メモリが膨らみやすい(解放タイミングが不確定)
- 予測不能な遅延(リアルタイム処理に不向き)
Rustの革新点
安全性の保証をGCではなくコンパイラのルール検査で実現。ランタイムコストゼロで高い安全性を担保する。