Skip to content

Commit

Permalink
Guide: match
Browse files Browse the repository at this point in the history
  • Loading branch information
steveklabnik committed Jul 8, 2014
1 parent c9e2ca0 commit daea9f4
Showing 1 changed file with 96 additions and 0 deletions.
96 changes: 96 additions & 0 deletions src/doc/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,102 @@ Enums

## Match

Often, a simple `if`/`else` isn't enough, because you have more than two
possible options. And `else` conditions can get incredibly complicated. So
what's the solution?

Rust has a keyword, `match`, that allows you to replace complicated `if`/`else`
groupings with something more powerful. Check it out:

```rust
let x = 5i;

match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
4 => println!("four"),
5 => println!("five"),
_ => println!("something else"),
}
```

`match` takes an expression, and then branches based on its value. Each 'arm' of
the branch is of the form `val => expression`. When the value matches, that arm's
expression will be evaluated. It's called `match` because of the term 'pattern
matching,' which `match` is an implementation of.

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

```{ignore,notrust}
error: non-exhaustive patterns: `_` not covered
```

In other words, Rust is trying to tell us we forgot a value. Because `x` is an
integer, Rust knows that it can have a number of different values. For example,
`6i`. But without the `_`, there is no arm that could match, and so Rust refuses
to compile. `_` is sort of 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 `x`, and so our program will now compile.

`match` statements also destructure enums, as well. Remember this code from the
section on enums?

```{rust}
let x = 5i;
let y = 10i;
let ordering = x.cmp(&y);
if ordering == Less {
println!("less");
} else if ordering == Greater {
println!("greater");
} else if ordering == Equal {
println!("equal");
}
```

We can re-write this as a `match`:

```{rust}
let x = 5i;
let y = 10i;
match x.cmp(&y) {
Less => println!("less"),
Greater => println!("greater"),
Equal => println!("equal"),
}
```

This version has way less noise, and it also checks exhaustively to make sure
that we have covered all possible variants of `Ordering`. With our `if`/`else`
version, if we had forgotten the `Greater` case, for example, our program would
have happily compiled. If we forget in the `match`, it will not. Rust helps us
make sure to cover all of our bases.

`match` is also an expression, which means we can use it on the right hand side
of a `let` binding. We could also implement the previous line like this:

```
let x = 5i;
let y = 10i;
let result = match x.cmp(&y) {
Less => "less",
Greater => "greater",
Equal => "equal",
};
println!("{}", result);
```

In this case, it doesn't make a lot of sense, as we are just making a temporary
string where we don't need to, but sometimes, it's a nice pattern.

## Looping

for
Expand Down

0 comments on commit daea9f4

Please sign in to comment.