Rustの 列挙型(enum) は、他の言語のEnumよりも全然多機能で、Rustという言語の「安全性」と「表現力」を支えるRust的に重要な機能です。
単なる「定数のリスト」ではなく、 「データの型を拡張できる仕組み」 として理解すると分かりやすくなるかもしれません。

概要:列挙型とは?
列挙型(enum)は、 「いくつかの選択肢のうち、いずれか一つ」 の状態を表現するデータ構造です。
例えば、「信号機の色」なら「赤・黄・青」のいずれか一つ、「メッセージの送信状態」なら「成功・失敗・待機」のいずれか一つです。
enum TrafficLight {
Red,
Yellow,
Green,
}
Rustの列挙型ならではの大きな特徴
他の言語のEnumと大きく異なるのはここからです。
① 各バリアントに「データ」を持たせられる
これがRustのenumの最大の強みです。ただのラベルではなく、それぞれの選択肢に異なる型のデータを持たせることができます。
enum Message {
Quit, // データなし
Move { x: i32, y: i32 }, // 構造体のようなデータ
Write(String), // 文字列データ
ChangeColor(i32, i32, i32), // タプルのようなデータ
}
C言語やJavaのenumでは、全ての選択肢が同じ形である必要がありますが、Rustでは 「終了」という空の状態と「座標移動」という数値データを持つ状態を共存 させられます。
② match式による強力なパターンマッチング
Rustのコンパイラは、enumを match 式で扱う際、 「全ての選択肢(バリアント)が網羅されているか」 を厳格にチェックします。
let msg = Message::Write(String::from("hello"));
match msg {
Message::Quit => println!("終了"),
Message::Move { x, y } => println!("座標: {}, {}", x, y),
Message::Write(text) => println!("メッセージ: {}", text),
// ここで ChangeColor の処理を書き忘れるとコンパイルエラーになる!
Message::ChangeColor(r, g, b) => println!("色変更"),
}
これにより、新しい状態を追加したときに、その処理を書き忘れるというバグを未然に防ぐことができます。
③ メソッドを実装できる(impl)
構造体(struct)と同様に、列挙型に対しても impl ブロックを使ってメソッドを定義できます。 これにより、データの「状態」とその状態に基づく「振る舞い」をひとまとめに管理できます。
例えば、Webブラウザの操作をシミュレートする WebEvent という列挙型にメソッドを追加してみましょう。
enum WebEvent {
PageLoad,
PageUnload,
KeyPress(char),
Paste(String),
}
impl WebEvent {
// 列挙型に定義したメソッド
fn inspect(&self) {
match self {
WebEvent::PageLoad => println!("ページがロードされました"),
WebEvent::PageUnload => println!("ページが閉じられました"),
// バリアントの中身(データ)を利用することも可能
WebEvent::KeyPress(c) => println!("キーが押されました: {}", c),
WebEvent::Paste(s) => println!("テキストが貼り付けられました: \"{}\"", s),
}
}
}
fn main() {
let pressed = WebEvent::KeyPress('A');
let pasted = WebEvent::Paste(String::from("Rustの世界"));
// メソッドの呼び出し
pressed.inspect();
pasted.inspect();
}
列挙型を使うメリット
- 型安全性: 文字列で
"Success"や"Error"と管理するのと違い、スペルミスによるバグが起きません。 - 「存在しない状態」を排除:
Option<T>(値があるか空か)やResult<T, E>(成功か失敗か)といった、Rustの根幹をなす仕組みもすべてこの列挙型でできています。 - コードが簡潔になる: 構造体だと「状態フラグ」と「その時に使うデータ」を別々に管理して複雑になりがちですが、enumなら一つにまとめられます。
用途
Rustの列挙型(enum)は、 「状態を厳密に管理したい場面」 で非常に強力です。構造体が「データの塊」なら、列挙型は 「排他的な選択肢(どれか一つだけ)」 を表現するのに適しています。
具体的に有効な3つの場面を紹介します。
1. 複数の異なる「状態」を切り替えるとき
例:通信ステータス、ゲームの進行状況、UIの表示状態
「ロード中」「成功(データあり)」「エラー(メッセージあり)」という、同時に起こり得ない状態を管理する場面です。
- なぜ有効か?: 構造体でこれをやろうとすると、
dataとerror_messageの両方のフィールドを持ち、どちらかがnullかどうかをチェックする複雑なコードになりがちです。enumなら、**「成功ならデータのみ」「エラーならエラー文のみ」**を型として定義できるため、矛盾した状態(データがあるのにエラーメッセージもある、など)が発生しません。
2. 「種類は違うが、共通の処理」をさせたいとき
例:図形計算(円、四角、三角)、コマンド処理(移動、停止、攻撃)
形は違うけれど、どれも「面積を計算できる」とか「コマンドとして実行できる」という共通点がある場合です。
- なぜ有効か?: 異なる構造体を一つのリスト(配列)に混ぜることは通常できませんが、
enumでまとめればVec<Shape>のように一つの配列に放り込めます。そしてmatchを使って、種類に応じた計算式を安全に適用できます。
3. 値の「有無」や「成功・失敗」を扱うとき(Rustの核心)
例:検索結果(見つかった vs なかった)、ファイルの読み込み(成功 vs 失敗)
Rustの標準ライブラリで最も重要な Option<T> と Result<T, E> も enum です。
- なぜ有効か?: 他の言語の
nullのように「値がないかもしれないのに、あると思ってアクセスしてクラッシュする」という事故を防げます。enumを使うことで、 「値がない可能性」をコンパイラが強制的に意識させてくれる ため、堅牢なプログラムになります。
ということでRustのEnumは他の言語とは全然異なる、ということでした。








