about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSteve Klabnik <steve@steveklabnik.com>2014-07-04 18:27:21 -0400
committerSteve Klabnik <steve@steveklabnik.com>2014-07-08 12:16:58 -0400
commitdaea9f4ad9bd8a391eb283fcc6f8e97e943c6342 (patch)
tree3e4c03bbe4643e82031ade6ca5e1a7db3c253b47
parentc9e2ca0dfad8f2aff48c64887b1ec4276929eced (diff)
downloadrust-daea9f4ad9bd8a391eb283fcc6f8e97e943c6342.tar.gz
rust-daea9f4ad9bd8a391eb283fcc6f8e97e943c6342.zip
Guide: match
-rw-r--r--src/doc/guide.md96
1 files changed, 96 insertions, 0 deletions
diff --git a/src/doc/guide.md b/src/doc/guide.md
index dc9608563e1..070dba8956d 100644
--- a/src/doc/guide.md
+++ b/src/doc/guide.md
@@ -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