---
title: enumとパターンマッチング
url: https://doc.liz6.com/ja/rust/02-type-system/02-enums-and-pattern-matching
locale: ja
area: rust
tags:
- rust
- type-system
date: 2026-06-30
modified: 2026-07-16
description: Rustのenumはタグ付き共用体(tagged union)であり、各variantは独立したデータを持ち、コンパイラがmatchで全てのvariantを網羅していることを保証します（網羅性チェック）。OptionとResultは言語組み込みではなく、標準ライブラリがenumを用いて定義しています——これは、enumがRustで最も表現力豊かな型構築子であることを証明しています。
---

# enumとパターンマッチング

> Rustのenumはタグ付き共用体(tagged union)であり、各variantは独立したデータを持ち、コンパイラがmatchで全てのvariantを網羅していることを保証します（網羅性チェック）。OptionとResultは言語組み込みではなく、標準ライブラリがenumを用いて定義しています——これは、enumがRustで最も表現力豊かな型構築子であることを証明しています。

## enumはtagged unionであり、単なる「列挙」ではない

Cのenumは単なる名前付き整数定数の集合に過ぎません。Rustのenumの各variantは異なるデータを持てる——それはタグ付き共用体です：

```rust
enum Message {
    Quit,                            // データなし — 純粋なタグ
    Move { x: i32, y: i32 },         // 匿名struct
    Write(String),                   // タプルvariant
    ChangeColor(u8, u8, u8),         // u8が3つのタプル
}
```

コンパイラは `Message` に対して、最大のvariant（`Move` = i32が2つ = 8バイト）を格納するのに十分なサイズを割り当て、さらにdiscriminant（タグ）フィールドを追加します。`Option<&T>` のようなnicheが存在するケースでは、タグの最適化が行われます。

## Option: Rustにnullはない

Tony Hoareはnullを「10億ドルのミス」と呼んでいます。Rustにはnullがありません——存在しないかもしれない値は `Option<T>` で表されます：

```rust
fn safe_div(a: i32, b: i32) -> Option<i32> {
    if b == 0 { None } else { Some(a / b) }
}
// 呼び出し側はNoneの場合を処理しなければならない：
match safe_div(10, 0) {
    Some(result) => println!("{}", result),
    None => println!("division by zero"),
}
```

コンパイラは `None` の場合の処理を強制します——チェックを忘れることは不可能です。`Option<T>` は特殊なnullマーカではなく通常の型なので、`Option` に対してmap、and_thenなどのcombinatorを使用できます。

## Result: エラーも値である

例外の問題は、制御フローを壊してしまうことです——関数のシグネチャからは、どのような例外を投げる可能性があるか分かりません。`Result<T, E>` はエラーを戻り値の一部にします：

```rust
fn parse(s: &str) -> Result<i32, std::num::ParseIntError> {
    s.parse()                        // Resultを返す。throwではない
}
```

呼び出し側は `Result<i32, ParseIntError>` を見ることで——この関数は成功時に `i32` を返し、失敗時に解析エラーを返す可能性がある——ことが分かります。隠れた制御フローはありません。

## Match: コンパイル時の網羅性チェック

```rust
match number {
    1 => "one",
    2 => "two",
    // _ => "other",                 // この行が欠けている場合、コンパイルエラー：
                                     // "non-exhaustive patterns"
}
```

コンパイラは、matchが全ての可能なvariantを網羅しているかどうかをチェックします。型に新しいvariantが追加された場合（例えばenumに新しいメンバーが追加された場合）、その型に対するmatchが書かれている箇所はすべてコンパイルに失敗します——新しいケースを明示的に処理することを強制します。

## パターンの様々な形式

```rust
// デストラクチャリング
let (x, y, z) = (1, 2, 3);
let Point { x, y } = point;

// refパターン: moveせず、借用する
let ref r = value;                   // r: &T, valueはmoveされない

// match guard: 追加の条件
match num {
    n if n % 2 == 0 => "even",
    n if n > 10 => "big",
    _ => "other",
}

// @バインディング: パターンと変数バインディングを同時に実行
match opt {
    Some(v @ 1..=5) => println!("small: {}", v),
    Some(v) => println!("large: {}", v),
    None => (),
}

// if let / while let: 1つのvariantのみに関心がある場合のシンタックスシュガー
if let Some(v) = opt { process(v); }
while let Some(v) = iter.next() { process(v); }
```

## 参考

- **Rust Book**: 第6章 (Enums)、第18章 (Patterns)
- **Rust Reference**: Match expressions, Patterns

*Keywords: enum, Option, Result, match, pattern, if let, while let, exhaustiveness, tagged union*
