Rust

Rustとは

Rust は、メモリ安全性を言語仕様で保証するコンパイル型言語です。C や C++ と同等の実行速度を出しながら、メモリ破壊のバグをコンパイル時に弾くことを狙って設計されています。

fn main() {
    let message = String::from("Hello, Rust");
    println!("{message}");
}

Go や Java と違い、ガベージコレクションを持ちません。それでもメモリ解放を手書きしないで済むのは、次に説明する所有権システムがあるからです。

所有権・借用・ライフタイム

Rust の中心にあるのが所有権(ownership)です。値には常にただ1つの所有者がいて、所有者がスコープを抜けた時点でメモリが解放されます。

let a = String::from("data");
let b = a;          // 所有権が b へ移動(ムーブ)
// println!("{a}"); // ここで a を使うとコンパイルエラー

値を渡さずに一時的に使いたいときは借用(borrow)します。借用には次の規則があり、コンパイラがこれを検査します。

規則内容
共有参照読み取り専用の借用は同時に何個でも持てる
可変参照書き換え可能な借用は同時に1つだけ
参照の寿命参照は、参照先の値より長く生き残れない(ライフタイム)

この3つを守らせるだけで、解放済みメモリへのアクセスや複数スレッドからの同時書き換えといった不具合が実行前にエラーになります。所有権の考え方に慣れるまでがRustの最初の山です。

並行処理との相性

[[並行処理と非同期]] を安全に書けることが Rust の実用上の強みです。可変参照が同時に1つしか作れないという規則は、そのまま「データ競合が起きない」という保証になります。コンパイルが通れば競合しない、という性質は fearless concurrency と呼ばれます。

非同期処理は async / await と、[[tokio(非同期ランタイム)]] などの非同期ランタイムを組み合わせて書きます。ランタイムは言語標準に含まれず、用途に応じて選びます。

async fn fetch_all() {
    let (a, b) = tokio::join!(fetch("/a"), fetch("/b")); // 2つを並行に待つ
}

どこで使われているか

  • CLIツール・バックエンド — 単一バイナリに固められ、常駐しても消費メモリが安定する
  • [[WebAssembly]] — ブラウザで動かすネイティブコードの主要な生成元。Rust は wasm 向けの公式サポートが厚い
  • [[マイコン]] や組み込み — ランタイムなしで動かせるため、OSの無い環境でも使える
  • 既存システムの一部置き換え — C 互換の呼び出し規約を持ち、性能が要る部分だけを差し替えられる

[[Go]] と比べられることが多いですが、狙いが違います。Go は「言語仕様を小さくして書きやすさと並行処理を取る」方向、Rust は「実行時コストを払わずに安全性を取る」方向です。GCの停止時間が許されない領域や、メモリ使用量を細かく制御したい領域では Rust が選ばれます。

初学者向けポイント

  • 最初はコンパイルが通らないことに戸惑いますが、エラーメッセージが具体的な修正案まで出すため、指示に従うだけで直せることが多いです
  • パッケージ管理とビルドは cargo に統一されています。テスト・ドキュメント生成・ベンチマークも同じコマンド体系です。規模が大きくなったら [[Cargoワークスペース構成]] でクレートを分けます
  • 失敗しうる処理は例外ではなく Result 型で返します。? 演算子で呼び出し元へ委ねる書き方が基本で、[[エラーハンドリングとリトライ設計]] の考え方が型として現れます

関連技術とのつながり

  • [[並行処理と非同期]] — 所有権の規則がそのままデータ競合の防止になる
  • [[WebAssembly]] — ブラウザ向けにコンパイルする主要言語のひとつ
  • [[Go]] — 同じ「速いサーバーサイド言語」でも、GCの有無と設計思想が対照的
  • [[エラーハンドリングとリトライ設計]] — 例外ではなく Result 型で失敗を表現する
  • [[マイコン]] — ランタイム不要のため組み込み用途でも使える
  • [[tokio(非同期ランタイム)]] — async / await を実際に走らせるランタイム。サーバー用途の事実上の標準
  • [[Cargoワークスペース構成]] — 複数クレートを1リポジトリで束ね、再ビルド範囲とテスト単位を分ける
Q: Rustがガベージコレクションなしでメモリ安全を保てる理由はどれ?
- [ ] 実行時にメモリ使用量を監視しているから
- [x] 所有権と借用の規則をコンパイル時に検査しているから
- [ ] メモリを解放しない設計だから
解説: 値の所有者は常に1つで、スコープを抜けた時点で解放されます。この規則をコンパイラが検査するため、実行時のGCが不要になります。

Q: Rustの可変参照(書き換え可能な借用)についての正しい説明はどれ?
- [ ] 同時にいくつでも作れる
- [x] 同時に1つしか作れない
- [ ] 共有参照と同時に作れる
解説: 可変参照は同時に1つだけという規則があり、これがデータ競合の防止につながっています。

Q: Rustで失敗しうる処理の結果を表す型はどれ?
- [x] Result
- [ ] Exception
- [ ] Nullable
解説: Rustは例外機構を持たず、`Result` 型で成功・失敗を表現します。`?` 演算子で呼び出し元へ伝播できます。