Match

簡單的 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 是「模式配對」(pattern matching)的實作。 模式(pattern)有一個單獨的章節會涵蓋所有可能的模式。

match 的許多優點之一是它的強制「徹底檢查」(exhaustiveness checking)。 舉例來說,當我們刪除最後一條有著 _ 的執行分支,編譯器將會給我們錯誤訊息:

error: non-exhaustive patterns: `_` not covered

Rust 告訴我們,我們忘了一個值。 編譯器從 x 推斷出它可能是任何 32 位元正整數;從 1 到 2,147,483,647 都有可能。 而 _ 就像是「全部接住」(catch-all) 沒有 被特別列在 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)的可能變體們:

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 陳述式,它可被視為 match 的簡略版。

commit fc4bb5f