マッチ

しばしば、2つ以上の可能な処理が存在するためや、分岐条件が非常に複雑になるために単純な if/else では充分でない場合があります。 Rustにはキーワード match が存在し、複雑な if/else のグループをさらに強力なもので置き換えられます。 以下の例を見てみましょう:

fn main() { let x = 5; match x { 1 => println!("one"), 2 => println!("two"), 3 => println!("three"), 4 => println!("four"), 5 => println!("five"), _ => println!("something 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 束縛の右側や式が使われているところで利用することができるということを意味しています。

fn main() { let x = 5; let number = match x { 1 => "one", 2 => "two", 3 => "three", 4 => "four", 5 => "five", _ => "something else", }; }
let x = 5;

let number = match x {
    1 => "one",
    2 => "two",
    3 => "three",
    4 => "four",
    5 => "five",
    _ => "something else",
};

このようにして、ある型から他の型への変換がうまく書ける場合があります。 この例では整数が String に変換されています。

列挙型に対するマッチ

match の他の重要な利用方法としては列挙型のバリアントを処理することがあります:

fn main() { 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), }; } }
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 letmatch の短縮形と捉えることができます。