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:
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:
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.
Another important use of the match
`match` keyword is to process the possible
variants of an 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), }; }
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`.