Rustの列挙型(Enum)の使い方とパターンマッチング

先生

RustのEnumは、データ構造の表現力を高め、パターンマッチングで安全に処理できる優れもの!

Rustの列挙型(Enum)とは?基本を解説

Rustの列挙型(Enum)は、複数の可能性のある値を一つにまとめるための強力なツールです。CやC++のEnumとは異なり、RustのEnumは単なる整数の別名ではなく、より複雑なデータ構造を表現できます。これにより、コードの可読性と安全性が向上します。

例えば、Web APIからのレスポンスを考えてみましょう。レスポンスは成功、失敗、または保留中のいずれかである可能性があります。これをEnumで表現すると、以下のように記述できます。

enum ApiResponse {
    Success(String),
    Failure(i32, String),
    Pending
}

この例では、ApiResponse Enumは3つのバリアント(Success, Failure, Pending)を持っています。SuccessString型のデータを、Failurei32型とString型のデータを、Pendingはデータを持っていません。このように、各バリアントは異なる型のデータを持つことができ、非常に柔軟な表現が可能です。

Enumの定義方法と基本的な使い方

Enumを定義するには、enumキーワードを使用します。上記のApiResponseの例のように、各バリアントはコンマで区切って列挙します。バリアントがデータを持つ場合は、その型を指定します。

Enumのインスタンスを作成するには、バリアント名を指定し、必要なデータを提供します。

let success = ApiResponse::Success("Data received successfully!".to_string());
let failure = ApiResponse::Failure(500, "Internal Server Error".to_string());
let pending = ApiResponse::Pending;

Enumのインスタンスを操作するには、パターンマッチングを使用します。パターンマッチングは、Enumのバリアントに基づいて異なる処理を実行するための強力な機能です。

パターンマッチングでEnumを使いこなす

パターンマッチングは、match式を使用して行います。match式は、Enumのインスタンスと複数のパターンを比較し、最初に一致したパターンに対応するコードブロックを実行します。

fn process_response(response: ApiResponse) {
    match response {
        ApiResponse::Success(message) => {
            println!("Success: {}", message);
        }
        ApiResponse::Failure(code, message) => {
            println!("Failure: Code = {}, Message = {}", code, message);
        }
        ApiResponse::Pending => {
            println!("Pending...");
        }
    }
}

この例では、process_response関数はApiResponse Enumを受け取り、そのバリアントに基づいて異なるメッセージを出力します。_パターンを使用すると、すべてのバリアントを網羅する必要がなくなります。

fn process_response(response: ApiResponse) {
    match response {
        ApiResponse::Success(message) => {
            println!("Success: {}", message);
        }
        ApiResponse::Failure(code, message) => {
            println!("Failure: Code = {}, Message = {}", code, message);
        }
        _ => {
            println!("Other status");
        }
    }
}

Option型とResult型:Enumの応用例

RustのOption型とResult型は、Enumの強力な応用例です。Option型は、値が存在するかどうかを表します(Some(T) or None)。Result型は、処理が成功したか失敗したかを表します(Ok(T) or Err(E))。

enum Option<T> {
    Some(T),
    None,
}

enum Result<T, E> {
    Ok(T),
    Err(E),
}

Option型は、値が存在しない可能性がある場合に便利です。例えば、検索結果が見つからなかった場合などに使用できます。

fn find_user(id: i32) -> Option<String> {
    // ユーザーを検索するロジック
    if id == 1 {
        Some("John Doe".to_string())
    } else {
        None
    }
}

Result型は、エラーハンドリングに役立ちます。処理が失敗した場合に、エラー情報を返すことができます。

fn divide(x: i32, y: i32) -> Result<i32, String> {
    if y == 0 {
        Err("Cannot divide by zero".to_string())
    } else {
        Ok(x / y)
    }
}

参考リンク

まとめ

Rustの列挙型(Enum)は、複数の可能性のある値を安全かつ効率的に表現するための強力なツールです。パターンマッチングと組み合わせることで、Enumのバリアントに基づいて異なる処理を柔軟に実行できます。Option型とResult型は、Enumの応用例として、値の存在の有無やエラーハンドリングに役立ちます。Enumを使いこなすことで、より安全で可読性の高いRustコードを書くことができます。