copyediting: match
This commit is contained in:
parent
64f4021c40
commit
9aa4b643c4
@ -1,13 +1,13 @@
|
||||
% Match
|
||||
|
||||
Often, a simple `if`/`else` isn't enough, because you have more than two
|
||||
Often, a simple `if`/`else` isn’t enough, because you have more than two
|
||||
possible options. Also, `else` conditions can get incredibly complicated, so
|
||||
what's the solution?
|
||||
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}
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
match x {
|
||||
@ -21,11 +21,14 @@ match x {
|
||||
```
|
||||
|
||||
`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.
|
||||
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. There’s an [entire section on
|
||||
patterns][patterns] coming up next, that covers all the options that fit here.
|
||||
|
||||
So what's the big advantage here? Well, there are a few. First of all, `match`
|
||||
[patterns]: patterns.html
|
||||
|
||||
So what’s the big advantage here? Well, there are a few. First of all, `match`
|
||||
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:
|
||||
|
||||
@ -36,121 +39,24 @@ 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,
|
||||
`6`. Without the `_`, however, there is no arm that could match, and so Rust refuses
|
||||
to compile. `_` acts like a *catch-all arm*. If none of the other arms match,
|
||||
to compile. `_` 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 `x`, and so our program will compile successfully.
|
||||
|
||||
`match` statements also destructure enums, as well. Remember this code from the
|
||||
section on enums?
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
let ordering = cmp(x, y);
|
||||
|
||||
if ordering == Ordering::Less {
|
||||
println!("less");
|
||||
} else if ordering == Ordering::Greater {
|
||||
println!("greater");
|
||||
} else if ordering == Ordering::Equal {
|
||||
println!("equal");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We can re-write this as a `match`:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
match cmp(x, y) {
|
||||
Ordering::Less => println!("less"),
|
||||
Ordering::Greater => println!("greater"),
|
||||
Ordering::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` expressions also allow us to get the values contained in an `enum`
|
||||
(also known as destructuring) as follows:
|
||||
|
||||
```{rust}
|
||||
enum OptionalInt {
|
||||
Value(i32),
|
||||
Missing,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = OptionalInt::Value(5);
|
||||
let y = OptionalInt::Missing;
|
||||
|
||||
match x {
|
||||
OptionalInt::Value(n) => println!("x is {}", n),
|
||||
OptionalInt::Missing => println!("x is missing!"),
|
||||
}
|
||||
|
||||
match y {
|
||||
OptionalInt::Value(n) => println!("y is {}", n),
|
||||
OptionalInt::Missing => println!("y is missing!"),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
That is how you can get and use the values contained in `enum`s.
|
||||
It can also allow us to handle errors or unexpected computations; for example, a
|
||||
function that is not guaranteed to be able to compute a result (an `i32` here)
|
||||
could return an `OptionalInt`, and we would handle that value with a `match`.
|
||||
As you can see, `enum` and `match` used together are quite useful!
|
||||
|
||||
`match` is also an expression, which means we can use it on the right-hand
|
||||
side of a `let` binding or directly where an expression is used. We could
|
||||
also implement the previous example like this:
|
||||
side of a `let` binding or directly where an expression is used:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
```rust
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
println!("{}", match cmp(x, y) {
|
||||
Ordering::Less => "less",
|
||||
Ordering::Greater => "greater",
|
||||
Ordering::Equal => "equal",
|
||||
});
|
||||
}
|
||||
let numer = match x {
|
||||
1 => "one",
|
||||
2 => "two",
|
||||
3 => "three",
|
||||
4 => "four",
|
||||
5 => "five",
|
||||
_ => "something else",
|
||||
};
|
||||
```
|
||||
|
||||
Sometimes, it's a nice pattern.
|
||||
Sometimes, it’s a nice way of converting things.
|
||||
|
Loading…
Reference in New Issue
Block a user