注意: 最新版のドキュメントをご覧ください。この第1版ドキュメントは古くなっており、最新情報が反映されていません。リンク先のドキュメントが現在の Rust の最新のドキュメントです。
しばしば、2つ以上の可能な処理が存在するためや、分岐条件が非常に複雑になるために単純な if
/else
では充分でない場合があります。
Rustにはキーワード match
が存在し、複雑な if
/else
のグループをさらに強力なもので置き換えられます。
以下の例を見てみましょう:
let x = 5; match x { 1 => println!("one"), 2 => println!("two"), 3 => println!("three"), 4 => println!("four"), 5 => println!("five"), _ => println!("something else"), }
match
は一つの式とその式の値に基づく複数のブランチを取ります。
一つ一つの「腕」は val => expression
という形式を取ります。
値がマッチした時に、対応する腕の式が評価されます。
このような式が match
と呼ばれるのは「パターンマッチ」という用語に由来します。
パターン のセクションではこの部分に書けるすべてのパターンを説明しています。
数ある match
の利点のうちの一つに「網羅性検査」を行なうということが上げられます。
例えば最後の _
の腕を消すと、コンパイラはエラーを出します。
error: non-exhaustive patterns: `_` not covered
Rustは何かしらの値を忘れていると教えてくれています。
コンパイラは x
が任意の32bitの値、例えば-2,147,483,648から2,147,483,647を取り得ると推論します。
_
が「がらくた入れ」として振舞います、 match
の腕で指定され なかった 可能な値全てを捕捉します。
先の例で見た通り、 match
の腕は 1〜5の値を書いたので、 x
が6、あるいは他の値だった時は _
に捕捉されます。
match
は式でもあります、これはつまり let
束縛の右側や式が使われているところで利用することができるということを意味しています。
let x = 5; let number = match x { 1 => "one", 2 => "two", 3 => "three", 4 => "four", 5 => "five", _ => "something else", };
このようにして、ある型から他の型への変換がうまく書ける場合があります。
この例では整数が String
に変換されています。
match
の他の重要な利用方法としては列挙型のバリアントを処理することがあります:
enum Message { Quit, ChangeColor(i32, i32, i32), Move { x: i32, y: i32 }, Write(String), } fn quit() { /* ... */ } fn change_color(r: i32, g: i32, b: i32) { /* ... */ } fn move_cursor(x: i32, y: i32) { /* ... */ } fn process_message(msg: Message) { match msg { Message::Quit => quit(), Message::ChangeColor(r, g, b) => change_color(r, g, b), Message::Move { x: x, y: y } => move_cursor(x, y), Message::Write(s) => println!("{}", s), }; }
繰り返しになりますが、Rustコンパイラは網羅性のチェックを行い、列挙型のすべてのバリアントに対して、マッチする腕が存在することを要求します。
もし、一つでもマッチする腕のないバリアントを残している場合、 _
を用いるか可能な腕を全て書くかしなければコンパイルエラーが発生します。
先ほど説明した値に対する match
の利用とは異なり、列挙型のバリアントに基いた分岐に if
を用いることはできません。
列挙型のバリアントに基いた分岐には if let
文を用いることが可能です。 if let
は match
の短縮形と捉えることができます。