Match

Often, a simple if`if`/else`elseisn’t enough, because you have more than two possible options. Also, conditions can get quite complex. Rust has a keyword,` isn’t enough, because you have more than two possible options. Also, conditions can get quite complex. Rust has a keyword, match`match, that allows you to replace complicated`, that allows you to replace complicated if`if/`/else`else` groupings with something more powerful. Check it out:

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`matchtakes an expression and then branches based on its value. Each ‘arm’ of the branch is of the form` takes an expression and then branches based on its value. Each ‘arm’ of the branch is of the form val => expression`val => expression. When the value matches, that arm’s expression will be evaluated. It’s called`. When the value matches, that arm’s expression will be evaluated. It’s called match`matchbecause of the term ‘pattern matching’, which` because of the term ‘pattern matching’, which match`match` is an implementation of. There’s an entire section on patterns that covers all the patterns that are possible here.

So what’s the big advantage? Well, there are a few. First of all, match`matchenforces ‘exhaustiveness checking’. Do you see that last arm, the one with the underscore (` enforces ‘exhaustiveness checking’. Do you see that last arm, the one with the underscore (_`_`)? If we remove that arm, Rust will give us an error:

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

In other words, Rust is trying to tell us we forgot a value. Because x`xis an integer, Rust knows that it can have a number of different values – for example,` is an integer, Rust knows that it can have a number of different values – for example, 6`6. Without the`. Without the _`_, however, there is no arm that could match, and so Rust refuses to compile the code.`, however, there is no arm that could match, and so Rust refuses to compile the code. _`_acts like a ‘catch-all arm’. If none of the other arms match, the arm with` acts like a ‘catch-all arm’. If none of the other arms match, the arm with _`_will, and since we have this catch-all arm, we now have an arm for every possible value of` will, and since we have this catch-all arm, we now have an arm for every possible value of x`x`, and so our program will compile successfully.

match`matchis also an expression, which means we can use it on the right-hand side of a` is also an expression, which means we can use it on the right-hand side of a let`let` binding or directly where an expression is used:

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",
};

Sometimes it’s a nice way of converting something from one type to another.

Matching on enums

Another important use of the match`match` keyword is to process the possible variants of an enum:

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),
    };
}

Again, the Rust compiler checks exhaustiveness, so it demands that you have a match arm for every variant of the enum. If you leave one off, it will give you a compile-time error unless you use _`_`.

Unlike the previous uses of match`match, you can’t use the normal`, you can’t use the normal if`ifstatement to do this. You can use the [` statement to do this. You can use the if let`if let` statement, which can be seen as an abbreviated form of match`match`.