Enum (Rust)

Rust の列挙型で、各バリアントがデータを持てる代数的データ型

Rust型システム

Rust の Enum とは

Rust の Enum (列挙型) は、各バリアントが異なるデータを持てる代数的データ型 (ADT) である。TypeScript の Discriminated Union に相当するが、パターンマッチとの組み合わせでコンパイラが網羅性を検証する。

基本的な使い方

enum Shape {
    Circle(f64),                    // 半径
    Rectangle(f64, f64),            // 幅, 高さ
    Triangle { base: f64, height: f64 }, // 名前付きフィールド
}

fn area(shape: &Shape) -> f64 {
    match shape {
        Shape::Circle(r) => std::f64::consts::PI * r * r,
        Shape::Rectangle(w, h) => w * h,
        Shape::Triangle { base, height } => base * height / 2.0,
    }
    // 全バリアントを網羅しないとコンパイルエラー
}

Option と Result

Rust には null がない。代わりに Option<T>Result<T, E> で値の有無やエラーを表現する。

// Option: 値があるかないか
fn find_user(id: &str) -> Option<User> {
    // Some(user) or None
}

let user = find_user("123");
match user {
    Some(u) => println!("Found: {}", u.name),
    None => println!("Not found"),
}

// Result: 成功か失敗か
fn parse_config(path: &str) -> Result<Config, ConfigError> {
    // Ok(config) or Err(error)
}

let config = parse_config("config.toml")?; // ? で早期リターン

TypeScript の Discriminated Union との比較

// TypeScript: Discriminated Union
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'rectangle'; width: number; height: number };

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle': return Math.PI * shape.radius ** 2;
    case 'rectangle': return shape.width * shape.height;
  }
}
観点 Rust Enum TypeScript DU
網羅性チェック コンパイルエラー ESLint ルールで検出
パターンマッチ match (ネイティブ) switch
メソッド定義 impl で直接定義 関数で外部定義
メモリ効率 タグ + 最大バリアントのサイズ オブジェクト

Enum にメソッドを定義

impl Shape {
    fn describe(&self) -> String {
        match self {
            Shape::Circle(r) => format!("Circle with radius {}", r),
            Shape::Rectangle(w, h) => format!("{}x{} Rectangle", w, h),
            Shape::Triangle { base, height } => format!("Triangle {}x{}", base, height),
        }
    }
}

Lambda でのエラーハンドリング

#[derive(Debug)]
enum AppError {
    NotFound(String),
    Unauthorized,
    Internal(String),
}

impl AppError {
    fn status_code(&self) -> u16 {
        match self {
            AppError::NotFound(_) => 404,
            AppError::Unauthorized => 401,
            AppError::Internal(_) => 500,
        }
    }
}

実務での活用方法は関連書籍にも詳しい。

関連用語