Skip to content

Commit b1ae09e

Browse files
committed
auto merge of #15434 : steveklabnik/rust/guide_match, r=brson
2 parents b733592 + daea9f4 commit b1ae09e

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

src/doc/guide.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,102 @@ do that with `match`.
12641264

12651265
## Match
12661266

1267+
Often, a simple `if`/`else` isn't enough, because you have more than two
1268+
possible options. And `else` conditions can get incredibly complicated. So
1269+
what's the solution?
1270+
1271+
Rust has a keyword, `match`, that allows you to replace complicated `if`/`else`
1272+
groupings with something more powerful. Check it out:
1273+
1274+
```rust
1275+
let x = 5i;
1276+
1277+
match x {
1278+
1 => println!("one"),
1279+
2 => println!("two"),
1280+
3 => println!("three"),
1281+
4 => println!("four"),
1282+
5 => println!("five"),
1283+
_ => println!("something else"),
1284+
}
1285+
```
1286+
1287+
`match` takes an expression, and then branches based on its value. Each 'arm' of
1288+
the branch is of the form `val => expression`. When the value matches, that arm's
1289+
expression will be evaluated. It's called `match` because of the term 'pattern
1290+
matching,' which `match` is an implementation of.
1291+
1292+
So what's the big advantage here? Well, there are a few. First of all, `match`
1293+
does 'exhaustiveness checking.' Do you see that last arm, the one with the
1294+
underscore (`_`)? If we remove that arm, Rust will give us an error:
1295+
1296+
```{ignore,notrust}
1297+
error: non-exhaustive patterns: `_` not covered
1298+
```
1299+
1300+
In other words, Rust is trying to tell us we forgot a value. Because `x` is an
1301+
integer, Rust knows that it can have a number of different values. For example,
1302+
`6i`. But without the `_`, there is no arm that could match, and so Rust refuses
1303+
to compile. `_` is sort of like a catch-all arm. If none of the other arms match,
1304+
the arm with `_` will. And since we have this catch-all arm, we now have an arm
1305+
for every possible value of `x`, and so our program will now compile.
1306+
1307+
`match` statements also destructure enums, as well. Remember this code from the
1308+
section on enums?
1309+
1310+
```{rust}
1311+
let x = 5i;
1312+
let y = 10i;
1313+
1314+
let ordering = x.cmp(&y);
1315+
1316+
if ordering == Less {
1317+
println!("less");
1318+
} else if ordering == Greater {
1319+
println!("greater");
1320+
} else if ordering == Equal {
1321+
println!("equal");
1322+
}
1323+
```
1324+
1325+
We can re-write this as a `match`:
1326+
1327+
```{rust}
1328+
let x = 5i;
1329+
let y = 10i;
1330+
1331+
match x.cmp(&y) {
1332+
Less => println!("less"),
1333+
Greater => println!("greater"),
1334+
Equal => println!("equal"),
1335+
}
1336+
```
1337+
1338+
This version has way less noise, and it also checks exhaustively to make sure
1339+
that we have covered all possible variants of `Ordering`. With our `if`/`else`
1340+
version, if we had forgotten the `Greater` case, for example, our program would
1341+
have happily compiled. If we forget in the `match`, it will not. Rust helps us
1342+
make sure to cover all of our bases.
1343+
1344+
`match` is also an expression, which means we can use it on the right hand side
1345+
of a `let` binding. We could also implement the previous line like this:
1346+
1347+
```
1348+
let x = 5i;
1349+
let y = 10i;
1350+
1351+
let result = match x.cmp(&y) {
1352+
Less => "less",
1353+
Greater => "greater",
1354+
Equal => "equal",
1355+
};
1356+
1357+
println!("{}", result);
1358+
```
1359+
1360+
In this case, it doesn't make a lot of sense, as we are just making a temporary
1361+
string where we don't need to, but sometimes, it's a nice pattern.
1362+
12671363
## Looping
12681364

12691365
for

0 commit comments

Comments
 (0)