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 / PythonRust
メモリ管理手動GCが自動所有権(コンパイル時)
ダングリング起きうる起きないコンパイルエラー
実行時コスト低いGCのオーバーヘッドあり低い(C++同等)
安全性開発者次第高い高い

GCのデメリット

  • Stop the World: GC実行中に処理が止まる
  • メモリが膨らみやすい(解放タイミングが不確定)
  • 予測不能な遅延(リアルタイム処理に不向き)

Rustの革新点

安全性の保証をGCではなくコンパイラのルール検査で実現。ランタイムコストゼロで高い安全性を担保する。

関連トピック

参考