Rustのパターンマッチングの深いボーリング
Emily Parker
Product Engineer · Leapcell

はじめに
Rustでは、パターンマッチングは、さまざまなパターンに基づいて異なる操作を実行できる強力な言語機能です。パターンマッチングは、enum型の操作、タプルや構造体のデストラクチャリング、条件式の処理など、さまざまなシナリオで使用できます。この記事では、Rustのパターンマッチング構文の詳細な紹介と、サンプルコードを通じてその使用法と利点を示します。
基本的な使い方
Rustでは、パターンマッチングにmatch
キーワードを使用します。match
式は複数のアームで構成され、各アームにはパターンと、パターンが一致したときに実行するコードブロックが含まれています。Rustはアームを順番に評価し、最初に一致したパターンに対応するブロックを実行します。以下に簡単な例を示します。
fn main() { let number = 3; match number { 1 => println!("One"), 2 => println!("Two"), 3 => println!("Three"), _ => println!("Other"), } }
上記のコードでは、変数number
を定義し、値3を代入します。次に、match
式を使用してnumber
と照合します。まず、Rustはパターン1
を持つ最初のアームをチェックします。number
は1ではないため、そのアームはスキップされます。2番目のアーム2
に進みますが、これも一致しません。最後に、3番目のアーム3
をチェックします。これは一致するため、ブロックを実行してThree
を出力します。
どのパターンも一致しない場合、最後のアンダースコア_
は、他の言語のdefault
と同様に、デフォルトケースとして機能し、対応するブロックを実行します。
Enum型のマッチング
Rustでは、enumは、複数の異なるバリアントのいずれかになり得る値を定義できる型です。パターンマッチングは、列挙型を処理する最も一般的な方法の1つであり、バリアントに応じて異なるロジックを実行できます。
次の例を考えてみましょう。ここでは、3つの異なるバリアントを持つMessage
というenumを定義します。Move
、Write
、ChangeColor
です。
enum Message { Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), }
次に、match
式を使用して、Message
のさまざまなバリアントを処理します。
fn process_message(msg: Message) { match msg { Message::Move { x, y } => println!("Move to coordinates (x={}, y={})", x, y), Message::Write(text) => println!("Write: {}", text), Message::ChangeColor(r, g, b) => println!("Change color to (r={}, g={}, b={})", r, g, b), } } fn main() { let msg1 = Message::Move { x: 10, y: 20 }; let msg2 = Message::Write(String::from("Hello, world!")); let msg3 = Message::ChangeColor(255, 0, 0); process_message(msg1); process_message(msg2); process_message(msg3); }
上記のコードでは、Message
enumをパラメータとして取る関数process_message
を定義します。match
式内では、異なるenumバリアントを異なるロジックで処理します。Message::Move
バリアントの場合、パターンをデストラクチャしてx
とy
を取得し、座標を出力します。Message::Write
の場合は、文字列を直接出力します。Message::ChangeColor
の場合は、r
、g
、b
をデストラクチャし、RGB値を出力します。
main
関数では、3つの異なるMessage
値を作成し、処理のためにprocess_message
に渡します。バリアントに基づいて、異なるロジックを実行します。
構造体のデストラクチャリングとマッチング
enumに加えて、Rustは構造体のデストラクチャリングとマッチングもサポートしています。構造体は、複数のフィールドで構成されるカスタムデータ型です。パターンを使用して構造体をデストラクチャリングし、フィールド値に基づいて操作を実行できます。
次の例を考えてみましょう。ここでは、2D空間内の点を表すPoint
という名前の構造体を定義します。
struct Point { x: i32, y: i32, }
次に、match
式を使用して、異なるPoint
構造体をデストラクチャリングして照合します。
fn process_point(point: Point) { match point { Point { x, y } => println!("Point coordinates: x={}, y={}", x, y), } } fn main() { let p1 = Point { x: 10, y: 20 }; let p2 = Point { x: -5, y: 15 }; process_point(p1); process_point(p2); }
上記のコードでは、Point
をパラメータとして取る関数process_point
を定義します。match
式では、パターンPoint { x, y }
を使用して構造体のフィールドをデストラクチャリングし、それらを出力します。
main
関数では、2つの異なるPoint
インスタンスを作成し、それらをprocess_point
に渡します。パターンマッチングを使用すると、構造体のフィールドに簡単にアクセスして操作できます。
if let
を使用したマッチングの簡略化
場合によっては、特定のパターンが一致するかどうかだけが重要で、他のパターンを処理する必要がないことがあります。このような場合、if let
式を使用すると、マッチングプロセスを簡略化できます。
次の例を考えてみましょう。ここでは、2つのバリアントNumber
とText
を持つValue
というenumを定義します。
enum Value { Number(i32), Text(String), }
次に、if let
を使用して、Value
インスタンスがNumber
であるかどうかを確認します。
fn main() { let value = Value::Number(42); if let Value::Number(n) = value { println!("The value is a number: {}", n); } else { println!("The value is not a number"); } }
上記のコードでは、Value
変数を定義し、Value::Number(42)
を代入します。次に、if let
を使用して、それがNumber
バリアントであるかどうかを確認します。そうであれば、数値をデストラクチャして出力します。そうでない場合は、数値ではないというメッセージを出力します。
if let
を使用すると、特に1つのパターンだけに関心がある場合に、コードをより簡潔で読みやすくすることができます。
複数のパターンのマッチング
場合によっては、複数のパターンを一致させ、同じコードブロックを実行したいことがあります。Rustは、|
演算子を提供して、1つのアームで複数のパターンを一致させます。
次の例を考えてみましょう。ここでは、変数number
を定義し、複数のパターンを一致させます。
fn main() { let number = 42; match number { 0 | 1 => println!("Zero or one"), 2 | 3 | 4 => println!("Two, three, or four"), _ => println!("Other"), } }
上記のコードでは、match
を使用してnumber
を評価します。最初のアームは、0 | 1
を使用して0と1の両方を一致させます。2番目のアームは、2 | 3 | 4
を使用して2、3、4を一致させます。最後のアンダースコア_
は、他のすべての値のデフォルトケースとして機能します。
|
演算子は、複数の値をクリーンに一致させ、コードの重複を回避するのに役立ちます。
if let
とwhile let
match
に加えて、Rustは条件付きパターンマッチングのためにif let
とwhile let
を提供します。
if let
式は、マッチングを実行し、条件が真の場合にブロックを実行します。一致しない場合は、何も起こりません。
while let
式はif let
のように機能しますが、パターンが一致する限り、プロセスをループで繰り返します。
以下に、両方を示す例を示します。
fn main() { let values = vec![Some(1), Some(2), None, Some(3)]; for value in values { if let Some(num) = value { println!("Number: {}", num); } else { println!("None"); } } let mut values = vec![Some(1), Some(2), None, Some(3)]; while let Some(value) = values.pop() { if let Some(num) = value { println!("Number: {}", num); } else { println!("None"); } } }
上記のコードでは、まずOption
値のベクターを定義します。for
ループとif let
を使用して、各要素がSome
であるかどうかを確認し、値を出力するか、「None」を出力します。
次に、別のベクターを定義し、while let
を使用して要素を1つずつポップします。要素がSome
である限り、その値を出力します。それ以外の場合は、「None」を出力します。
if let
とwhile let
を使用すると、条件を柔軟に一致させ、パターンを処理できます。
match
のエクゾースティブネスチェック
Rustでは、match
式はエクゾースティブです。これは、コンパイラがmatch
式ですべての可能なケースが処理されているかどうかをチェックして、何も見落とされないようにすることを意味します。
match
式がエクゾースティブでない場合、コンパイラは潜在的なエラーを防ぐために警告を発行します。エクゾースティブネスを保証するには、フォールバックケースとしてmatch
の最後に_
アームを追加できます。
以下に、エクゾースティブネスチェックを示す例を示します。
enum Color { Red, Green, Blue, } fn main() { let color = Color::Red; match color { Color::Red => println!("Red"), Color::Green => println!("Green"), // Missing the Color::Blue branch } }
上記のコードでは、3つのバリアントを持つenum Color
を定義します。次に、match
式を使用してcolor
変数を照合します。Color::Red
とColor::Green
のアームを提供しますが、Color::Blue
を省略します。
このコードをコンパイルしようとすると、Rustコンパイラは次の警告を生成します。
warning: non-exhaustive patterns: `Color::Blue` not covered
この警告は、match
式がすべての可能なケースを処理していないため、エクゾースティブではないことを示しています。
この問題を解決するには、_
ブランチを追加するか、すべてのenumバリアントを明示的に一致させることができます。
結論
パターンマッチングは、Rustの強力で柔軟な言語機能であり、さまざまなパターンに基づいて異なる操作を実行できます。
この記事では、Rustでのパターンマッチングの基本的な使用法、enumと構造体のマッチング、if let
とwhile let
を使用してマッチングロジックを簡略化、およびmatch
式でエクゾースティブネスを保証して、すべての可能なケースを処理する方法を紹介しました。
私たちはLeapcellです。Rustプロジェクトのホスティングに最適です。
Leapcellは、ウェブホスティング、非同期タスク、およびRedisのための次世代サーバーレスプラットフォームです。
多言語サポート
- Node.js、Python、Go、または Rust で開発します。
無制限のプロジェクトを無料でデプロイ
- 使用量に応じてのみ課金されます — リクエストも料金もありません。
比類なき費用対効果
- アイドル料金なしの従量課金制。
- 例: 25 ドルで、平均応答時間 60 ミリ秒で 694 万件のリクエストをサポートします。
合理化された開発者エクスペリエンス
- 簡単なセットアップのための直感的な UI。
- 完全に自動化された CI/CD パイプラインと GitOps 統合。
- 実用的な洞察のためのリアルタイムのメトリクスとロギング。
簡単なスケーラビリティと高いパフォーマンス
- 高い同時実行性を容易に処理するための自動スケーリング。
- 運用上のオーバーヘッドはゼロ — 構築に集中するだけです。
詳細については、ドキュメントをご覧ください!
X でフォローしてください: @LeapcellHQ