match は Rust の強力で柔軟な制御構造であり、複数のパターンに基づいて値を評価するために使用されます。これは、特にエラーハンドリングや複雑な条件分岐で非常に役立ちます。この記事では、Rust の match 構文の基本から応用までを完全に解説します。
match の基本構文
match は、値をパターンに照らして評価し、それにマッチしたブロックを実行します。基本的な構文は次のようになります。
rustmatch 値 {
パターン1 => 式1,
パターン2 => 式2,
_ => 式3, // デフォルトの場合
}
ここで、値 は評価される対象の変数で、パターン はその値が一致するかどうかを確認する条件です。_ は「デフォルト」を意味し、他のすべてのパターンが一致しない場合に使用されます。
match の例
次に、match の基本的な使用例を見てみましょう。
rustlet number = 3;
match number {
1 => println!("One"),
2 => println!("Two"),
3 => println!("Three"),
_ => println!("Other"),
}
このコードでは、number が 3 であるため、"Three" が出力されます。match は、最初に一致するパターンを見つけると、そこで評価が終了します。
複数のパターンを使う
match では、複数のパターンを同時に扱うことができます。これにより、同じ処理を複数の条件に対して適用することができます。
rustlet number = 5;
match number {
1 | 2 | 3 => println!("Small number"),
4 | 5 | 6 => println!("Medium number"),
_ => println!("Large number"),
}
ここでは、1、2、3 のいずれかに一致する場合は “Small number” が出力され、4、5、6 のいずれかに一致すれば “Medium number” が出力されます。
ガード条件を使う
match の各パターンには、条件を追加して細かい制御を行うこともできます。これを「ガード条件」と呼びます。ガード条件は、if を使ってパターンに追加することができます。
rustlet number = 7;
match number {
n if n < 5 => println!("Small"),
n if n >= 5 && n < 10 => println!("Medium"),
_ => println!("Large"),
}
この例では、n if n < 5 のように、特定の条件を付けてパターンをより詳細に制御しています。
Option 型と match
Rust では、Option 型を使用して値が存在するかどうかを表現します。この型は、Some(T) と None の2つのバリアントを持っています。match は Option 型の値を操作する際に非常に有用です。
rustlet some_number = Some(10);
match some_number {
Some(n) => println!("The number is {}", n),
None => println!("No number"),
}
ここでは、some_number が Some(10) であるため、"The number is 10" と出力されます。もし None だった場合、"No number" が出力されます。
Result 型と match
Result 型は、操作が成功した場合と失敗した場合を表現するために使用されます。Ok(T) と Err(E) の2つのバリアントがあり、これも match を使って処理できます。
rustlet result: Result<i32, &str> = Ok(5);
match result {
Ok(value) => println!("Success: {}", value),
Err(error) => println!("Error: {}", error),
}
この例では、result が Ok(5) であるため、"Success: 5" が出力されます。もし Err だった場合、そのエラーが処理されます。
match と型の一致
Rust の match はパターンマッチングの精度が高いため、型の一致も厳密に行われます。これにより、予期しないバグを防ぐことができます。例えば、次のコードでは型が一致しないためコンパイルエラーが発生します。
rustlet number = 3;
match number {
1 => println!("One"),
"three" => println!("Three"), // コンパイルエラー
_ => println!("Other"),
}
この場合、"three" は文字列型ですが、number は整数型であるため、コンパイルエラーが発生します。
match のデストラクチャリング
match では、構造体や列挙型などをデストラクチャリングして、内部の値にアクセスすることができます。例えば、タプルや構造体を使ったパターンマッチングが可能です。
rustlet point = (3, 4);
match point {
(0, 0) => println!("Origin"),
(x, 0) => println!("On the X axis: {}", x),
(0, y) => println!("On the Y axis: {}", y),
(x, y) => println!("Point at ({}, {})", x, y),
}
このコードでは、point が (3, 4) であるため、"Point at (3, 4)" と出力されます。
終わりに
match は Rust の中でも非常に強力で多用途に使える構造です。シンプルな条件分岐だけでなく、複雑なパターンマッチングやデストラクチャリングを活用することで、コードの可読性と保守性を向上させることができます。Option や Result 型との組み合わせは、エラーハンドリングを効率的に行うための強力な手段となります。
Rust の match は、他の多くのプログラミング言語の switch や if よりもはるかに強力で柔軟な制御構造を提供しており、その使い方をマスターすることで、より洗練された Rust コードを書けるようになります。
