Merge remote-tracking branch 'origin/ch6' into first-third-try

This commit is contained in:
Carol (Nichols || Goulding) 2016-07-08 15:45:54 -04:00
commit 99aba46d24
7 changed files with 451 additions and 390 deletions

View File

@ -28,8 +28,8 @@
- [Enums](ch06-01-enums.md)
- [Option](ch06-02-option.md)
- [Match](ch06-03-match.md)
- [if let](ch06-04-if-let.md)
- [Patterns](ch06-05-patterns.md)
- [Patterns](ch06-04-patterns.md)
- [if let](ch06-05-if-let.md)
- [Crates & Modules]()

View File

@ -1,12 +1,13 @@
# Enums
Next, lets look at a feature of Rust thats similar to structs, but also
different. Enumerations, or enums as theyre more commonly referred to,
are an extremely powerful feature of Rust. Enums are a feature that are in many
languages, but what they can do is different per-language. Rusts enums are
most similar to enums in functional languages.
Next, lets look at *enumerations*, which allow you to define a type by
enumerating its possible values. Commonly called "enums", these unlock a lot of
power in Rust when combined with pattern matching. Enums are a feature that are
in many languages, but what they can do is different per-language. Rusts enums
are most similar to "algebraic data types" in functional languages like F#,
OCaml, or Haskell.
Heres an example of an enum:
Heres an example of an enum definition:
```rust
enum IpAddrKind {
@ -16,10 +17,10 @@ enum IpAddrKind {
```
This enum represents the kind of an IP address. There are two major standards
used for IP addresses: version four, and version six. Any IP address can be either
a version four address, or a version six address. But it cannot be both kinds at
the same time. This is where enums get their name: they allow us to enumerate all
of the possible kinds that our value can have.
used for IP addresses: version four and version six. Any IP address can be
either a version four address or a version six address, but it cannot be both
kinds at the same time. This is where enums get their name: they allow us to
enumerate all of the possible kinds that our value can have.
We can create values of `IpAddrKind` like this:
@ -28,7 +29,7 @@ We can create values of `IpAddrKind` like this:
# V4,
# V6,
# }
#
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
```
@ -37,7 +38,7 @@ Note that the variants of the enum are namespaced under its name, and we use
the double colon to separate the two.
Enums have more tricks up their sleeves, however. Thinking more about our IP
address type, we dont have a way to store the actual data of the IP address,
address type, we dont have a way to store the actual data of the IP address;
we only know what kind it is. Given that you just learned about structs, you
might tackle this problem like this:
@ -64,8 +65,8 @@ let loopback = IpAddr {
```
Weve used a struct to bundle the two values together: now we keep the kind
with the value itself. This design isnt bad, exactly, but it wouldnt be
considered idiomatic Rust. We can represent the same thing with just an enum:
with the value itself. We can represent the same thing in a different way with
just an enum:
```rust
enum IpAddr {
@ -80,14 +81,14 @@ let loopback = IpAddr::V6(String::from("::1"));
We can attach data to each variant of the enum directly. No need for an extra
struct. But beyond that, this approach is better than using a struct alongside
our enum because we can attatch different kinds of data to each variant.
our enum because we can attach different kinds of data to each variant.
Imagine that instead of a `String`, we would prefer to store a `V4` as its four
individual components, while leaving the `V6` variant as a `String`. With our
individual components while leaving the `V6` variant as a `String`. With our
struct, wed be stuck. But enums deal with this case with ease:
```rust
enum IpAddr {
V4(u32, u32, u32, u32),
V4(u8, u8, u8, u8),
V6(String),
}
@ -97,8 +98,8 @@ let loopback = IpAddr::V6(String::from("::1"));
```
You can put any kind of data inside of an enum variant, including another enum!
The `IpAddr` enum is [in the standard library][IpAddr], but it embeds two different
structs inside of its variants:
The `IpAddr` enum is [in the standard library][IpAddr], but it embeds two
different structs inside of its variants:
```rust
struct Ipv4Addr {
@ -133,16 +134,21 @@ enum Message {
* `Write` includes a single `String`.
* `ChangeColor` includes three `i32`s.
We havent talked a lot about how to access the data inside an enum variant,
however. To do that, lets move on to some new Rust syntax thats especially
useful with enums: `match`.
This might seem overwhelming, but another way to look at the different enum
possibilities is that they are just like different kinds of struct definitions
that you already know, except without the `struct` keyword and they are grouped
together under the `Message` type. These structs could hold the same data that
these enum variants hold:
```
struct QuitMessage; // unit struct
struct MoveMessage {
x: i32,
y: i32,
}
struct WriteMessage(String); // tuple struct
struct ChangeColorMessage(i32, i32, i32); // tuple struct
```
Let's look at another enum in the standard library that is very common and
useful: `Option`.

View File

@ -1,9 +1,9 @@
# Option
Now that we have a handle on enums, let's combine them with a feature that we
talked a little bit about in the previous chapter: generics.
Now that we have had an introduction to enums, let's combine them with a
feature that we talked a little bit about in the previous chapter: generics.
Programming language design is often though of as which features you include,
Programming language design is often thought of as which features you include,
but it's also about which features you leave out. Rust does not have a feature
that is in many other languages: 'null'. In languages with this feature,
variables can have two states: null or not-null.
@ -30,8 +30,8 @@ Even with these problems, the concept that null is trying to express is still a
useful one: this is a value which is currently invalid or not present for some
reason. The problem isn't with the concept itself, but with the particular
implementation. As such, Rust does not have the concept of null, but we do have
a type which can encode the concept of a value being present. We call this type
`Option<T>`, and it looks like this:
an enum which can encode the concept of a value being present or not present. We
call this enum `Option<T>`, and it looks like this:
```rust
enum Option<T> {
@ -40,7 +40,7 @@ enum Option<T> {
}
```
This type is [provided by the standard library][option], and is so useful that
This enum is [provided by the standard library][option], and is so useful that
it's even in the prelude; you don't need to import it explicitly. Furthermore,
so are its variants: you can say `Some` and `None` directly, without prefixing
them with `Option::`.
@ -67,8 +67,8 @@ In short, because `Option<T>` and `T` are different types. That's a bit too
short though. Here's an example:
```rust,ignore
let x = 5;
let y = Some(5);
let x: i8 = 5;
let y: Option<i8> = Some(5);
let sum = x + y;
```
@ -76,8 +76,8 @@ let sum = x + y;
This will not compile. We get an error message like this:
```text
error: the trait `core::ops::Add<core::option::Option<_>>` is not implemented
for the type `_` [E0277]
error: the trait bound `i8: std::ops::Add<std::option::Option<i8>>` is not
satisfied [E0277]
let sum = x + y;
^~~~~
@ -85,17 +85,26 @@ let sum = x + y;
Intense! What this error message is trying to say is that Rust does not
understand how to add an `Option<T>` and a `T`. They're different types! This
shows one of the big advantages of an `Option<T>` type: if you have a type that
shows one of the big advantages of an `Option<T>`: if you have a value that
may or may not exist, you have to deal with that fact before you can assume it
exists. In other words, you have to convert an `Option<T>` to a `T` before you
can do `T` stuff with it. This helps catch one of the most common issues with
null, generally: assuming that something isn't null, when it actually is.
null, generally: assuming that something isn't null when it actually is.
So, how _do_ you get a `T` from an `Option<T>`? The option type has a large
number of methods that you can check out in [its documentation], and becoming
familiar with them will be extremely useful in your journey with Rust.
This is pretty powerful: in order to have a value that can possibly be null,
you have to explicitly opt in by making the type of that value an `Option<T>`.
Then, when you use that value, you are required to explicitly handle the case
when the value is null. Everywhere that a value has a type that isn't an
`Option<T>`, you *can* safely assume that the value isn't null. This was a
deliberate design decision for Rust to limit null's pervasiveness and increase
the safety of Rust code.
So, how _do_ you get a `T` from an `Option<T>`? The `Option<T>` enum has a
large number of methods that you can check out in [its documentation], and
becoming familiar with them will be extremely useful in your journey with Rust.
[its documentation]: ../std/option/enum.Option.html
But we want a deeper understanding than that. If we didn't have those methods
defined for us already, what would we do? For that, we need a new feature: `match`.
defined for us already, what would we do? And more generally, how do we get
the inner values out of any enum variant? We need a new feature: `match`.

View File

@ -1,10 +1,165 @@
# Match
Rust has an extremely powerful control-flow operator: `match`. It allows us to
compare a value against a series of patterns, and then execute code based on
how they compare. Remember the `Option<T>` type from the previous section?
compare a value against a series of patterns and then execute code based on
how they compare.
A `match` expression is kind of like a coin sorting machine. Coins slide down
a track that has variously sized holes along it, and each coin falls through the
first hole it encounters that it fits into. American coins are, in order of
diameter from smallest to largest diameter, dime ($0.10), penny ($0.01), nickel
($0.05), and quarter ($0.25). It is indeed strange that the dime is smallest
in diameter but not smallest in denomination.
We can write a function in Rust using a `match` expression that can take an
unknown American coin and, in a similar way as the coin counting machine,
determine which coin it is and return its value in cents:
```rust
enum Coin {
Dime,
Penny,
Nickel,
Quarter,
}
fn value_in_cents(coin: Coin) -> i32 {
match coin {
Coin::Dime => 10,
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Quarter => 25,
}
}
```
Let's break down the `match`! At a high-level, using `match` looks like this:
```text
match expression {
pattern => code,
}
```
First, we have the `match` keyword. Next, we have an expression. This feels
very similar to an expression used with `if`, but there's a big difference:
with `if`, the condition needs to return a boolean value. Here, it can be any
type.
Next, we have a "match arm". That's the part that looks like `pattern =>
code,`. We can have as many arms as we need to: our `match` above has four
arms. An arm has two parts: a pattern and some code. When the `match`
expression executes, it compares the resulting value against the pattern of
each arm, in order. If a pattern matches the value, the code associated
with that pattern is executed. If that pattern doesn't match the value,
execution continues to the next arm, much like a coin sorting machine.
The code associated with each arm is an expression, and the resulting value of
the code with the matching arm that gets executed is the value that gets
returned for the entire `match` expression.
Curly braces typically aren't used if the match arm code is short, as it is in
the above example where each arm just returns a value. If we wanted to run
multiple lines of code in a match arm, we can use curly braces. This code would
print out "Lucky penny!" every time the method was called with a `Coin::Penny`,
but would still return the last value of the block, `1`:
```rust
# enum Coin {
# Dime,
# Penny,
# Nickel,
# Quarter,
# }
#
fn value_in_cents(coin: Coin) -> i32 {
match coin {
Coin::Dime => 10,
Coin::Penny => {
println!("Lucky penny!");
1
},
Coin::Nickel => 5,
Coin::Quarter => 25,
}
}
```
Another useful feature of match arms is that they can create bindings to parts
of the values that match the pattern. From 1999 through 2008, the U.S. printed
quarters with different designs for each of the 50 states on one side. The other
coins did not get state designs, so only quarters have this extra attribute. We
can add this information to our `enum` by changing the `Quarter` variant to have
a `State` value:
```rust
enum UsState {
Alabama,
Alaska,
// ... etc
}
enum Coin {
Dime,
Penny,
Nickel,
Quarter(UsState),
}
```
Let's imagine that a friend of ours is trying to collect all 50 state quarters.
While we sort our loose change by coin type in order to count it, we're going
to call out the name of the state so that if it's one our friend doesn't have
yet, they can add it to their collection.
In the match statement to do this, the quarter case now has a binding, `state`,
that contains the value of the state of that quarter. The binding will only get
created if the coin matches the `Quarter` pattern. Then we can use the binding
in the code for that arm:
```rust
# #[derive(Debug)]
# enum UsState {
# Alabama,
# Alaska,
# }
#
# enum Coin {
# Dime,
# Penny,
# Nickel,
# Quarter(UsState),
# }
#
fn value_in_cents(coin: Coin) -> i32 {
match coin {
Coin::Dime => 10,
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
},
}
}
```
If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska))`, `coin` will
be `Coin::Quarter(UsState::Alaska)`. When we compare that value with each of the
match arms, none of them match until we reach `Coin::Quarter(state)`. At that
point, the binding for `state` will be the value `UsState::Alaska`. We can then
use that binding in the `println!`, thus getting the inner state value out of
the `Coin` enum variant for `Quarter`.
Remember the `Option<T>` type from the previous section, and that we wanted to
be able to get the inner `T` value out of the `Some` case? This will be very
similar! Instead of coins, we will be comparing to other patterns, but the way
that the `match` expression works remains the same as a coin sorting machine in
the way that we look for the first pattern that fits the value.
Let's say that we want to write a function that takes an `Option<i32>`, and
if there's a value inside, add one to it.
if there's a value inside, add one to it. If there isn't a value inside, we
want to return the `None` value and not attempt to add.
This function is very easy to write, thanks to `match`. It looks like this:
@ -21,27 +176,6 @@ let six = plus_one(five);
let none = plus_one(None);
```
Let's break down the `match`! At a high-level, the `match` expression looks
like this:
```text
match condition {
pattern => code,
}
```
First, we have the `match` keyword. Next, we have a condition. This feels very
similar to an `if` expression, but there's a big difference: with `if`, the
condition needs to be a boolean. Here, it can be any type.
Next, we have a "match arm". That's the part that looks like `pattern =>
code,`. We can have as many arms as we need to: our `match` above has two
arms. An arm has two parts: a pattern, and some code. When the `match`
expression executes, it compares the condition against the pattern of each arm,
in turn. If the pattern matches the condition, the associated code is executed,
and the rest of the patterns are not checked. If it doesn't match, execution
continues to the next arm.
Let's examine the first execution of `plus_one()` in more detail. In the above
example, `x` will be `Some(5)`. Let's compare that against each arm:
@ -55,35 +189,25 @@ Does `Some(5)` match `None`? No, it's the wrong variant. So let's continue.
Some(i) => Some(i + 1),
```
Does `Some(5)` match `Some(i)`? Why yes it does! We have the same variant. But
what about `i`? In a pattern like this, we can declare new bindings, similarly
to what we did with `let`. So in this case, the code part of the match arm will
have a binding, `i`, which corresponds to the `5`.
Does `Some(5)` match `Some(i)`? Why yes it does! We have the same variant. The
`i` binds to the value inside of the `Some`, so `i` has the value `5`. Then we
execute the code in that match arm: take `i`, which is `5`, add one to it, and
create a new `Some` value with our total inside.
With this arm, the code portion is `Some(i + 1)`. So we do exactly that: we
take `i`, which is `5`, add one to it, and create a new `Some` value with our
sum inside.
Because `match` is an expression, the value of the overall expression becomes
the value of the arm that executed. So the value of this `match` expression
will be `Some(6)`. And since our `match` is the only expression in the
function, the value of the `match` will be the value of the function, and so
`Some(6)` is our return value as well, which is exactly what we were shooting
for.
Now let's consider the second call. In this case, `x` is `None`. We enter the
`match`, and compare to the first arm:
Now let's consider the second call of `plus_one()`. In this case, `x` is
`None`. We enter the `match`, and compare to the first arm:
```text
None => None,
```
Does `None` match `None`? Yup! And so we return `None`. There's no value to add
to.
Does `None` match `None`? Yup! There's no value to add to. So we stop and
return the `None` value that is on the right side of the `=>`. We don't
check any other arms since we found one that matched.
Combining `match` and enums together is extremely powerful. You'll see this
pattern a lot in Rust code: `match` against an enum, binding to the data
inside, and then executing code based on it. It's a bit tricky at first, but
pattern a lot in Rust code: `match` against an enum, bind to the data
inside, and then execute code based on it. It's a bit tricky at first, but
once you get used to it, you'll wish you had it in languages that don't support
it. It's consistently a user favorite.
@ -100,8 +224,8 @@ fn plus_one(x: Option<i32>) -> Option<i32> {
}
```
A bug! We didn't handle the `None` case. Luckily, it's a bug Rust knows how to catch.
If we try to compile this code, we'll get an error:
A bug! We didn't handle the `None` case. Luckily, it's a bug Rust knows how to
catch. If we try to compile this code, we'll get an error:
```text
error: non-exhaustive patterns: `None` not covered [E0004]
@ -111,59 +235,23 @@ match x {
```
Rust knows that we did not cover every possible option, and even knows which
pattern we forgot! This is referred to as being "exhaustive", we must exhaust
every last option possible in order to be valid!
pattern we forgot! This is referred to as being "exhaustive": we must exhaust
every last option possible in order to be valid. Especially in the case of
`Option<T>`, when Rust prevents us from forgetting to explicitly handle the
`None` case, it protects us from assuming that we have a value when we might
have null and thus making the billion-dollar mistake we discussed in the
previous section.
This analysis isn't perfect, however. This will also error:
## The _ placeholder
```rust,ignore
# let some_u8_value = 0u8;
match some_u8_value {
0 => println!("zero"),
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
4 => println!("four"),
5 => println!("five"),
6 => println!("six"),
7 => println!("seven"),
// We won't write out all of the arms here, but imagine that there are more
// arms corresponding to the rest of the numbers.
254 => println!("two-hundred and fifty-four"),
255 => println!("two-hundred and fifty-five"),
}
```
Even though a `u8` can only have valid values of zero through 255, Rust isn't
quite smart enough to understand we've covered all the cases. In order to fix
this, we can use a special pattern, `_`:
What if we don't care about all of the possible values, though? Especially when
there are a lot of possible values for a type: a `u8` can have valid values of
zero through 255-- if we only care about 1, 3, 5, and 7, does this mean we must
list out 0, 2, 4, 6, 8, 9, all the way up through 255? Thankfully, no! We can
use a special pattern, `_`:
```rust
# let some_u8_value = 0u8;
match some_u8_value {
0 => println!("zero"),
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
4 => println!("four"),
5 => println!("five"),
6 => println!("six"),
7 => println!("seven"),
// ...
254 => println!("two-hundred and fifty-four"),
255 => println!("two-hundred and fifty-five"),
_ => panic!("can't ever happen"),
}
```
The `_` pattern matches anything at all, and so with it as the final pattern,
Rust can understand that we have all our bases covered. It's not only used for
this sort of exhastiveness issue, though. It's useful any time we don't want to
deal with a number of cases. Consider this scenario: if we wanted to print out
something one one, three, five, and seven:
```rust
# let some_u8_value = 0u8;
let some_u8_value = 0u8;
match some_u8_value {
1 => println!("one"),
3 => println!("three"),
@ -174,9 +262,11 @@ match some_u8_value {
```
The `_` pattern will match all the other cases, and `()` will do nothing, it's
the unit value.
the unit value. This way, we don't have to list individual match arms for all
the other possible values in order to say that we want to do nothing for all of
those-- the `_` is a placeholder for any value.
## More about patterns
As we've just seen, patterns are powerful, yet complex. Let's take a whole
section to cover all of the things that they can do.
As we've just seen, patterns are powerful. They can also get complex, so let's
take a whole section to cover all of the things that they can do.

197
src/ch06-04-patterns.md Normal file
View File

@ -0,0 +1,197 @@
# Patterns
We've mentioned 'patterns' a few times so far: they're used in `let` bindings,
in function arguments, and in `match` expressions. Patterns have a lot of
abilities, so in this section, we'll cover some of the most commonly used ones.
Any of these abilities work in any place where a pattern is used.
Let's start with an example that is similar to the last example in the previous
section:
```rust
let x = 1;
match x {
1 => println!("one"),
3 => println!("three"),
5 => println!("five"),
7 => println!("seven"),
_ => println!("anything else"),
}
```
This prints `one`. If we change `x` to have the value 4, this would print
`anything else`.
# Multiple patterns
What if we wanted to print the same thing for 1, 3, and 5? We could do:
```rust
let x = 1;
match x {
1 => println!("an odd number less than six"),
3 => println!("an odd number less than six"),
5 => println!("an odd number less than six"),
7 => println!("seven"),
_ => println!("anything else"),
}
```
But that repeats the string "an odd number less than six" multiple times. If we
had to change that string, it would be annoying to have to change it in three
places to make 1, 3, and 5 still have the same behavior.
Instead, we could match multiple patterns with `|`:
```rust
let x = 1;
match x {
1 | 3 | 5 => println!("an odd number less than six"),
7 => println!("seven"),
_ => println!("anything else"),
}
```
This match statement has the same functionality as the previous one, but we only
had to write the common `println!` once!
## Ranges
Another way to have multiple values match the same arm is using a range. If,
instead of the above where we treated 1, 3, and 5 the same, we wanted to treat
any number from 1 to 5 the same, we could do:
```rust
let x = 5;
match x {
1 ... 5 => println!("one through five"),
_ => println!("anything else"),
}
```
This prints `one through five`: 5 is included in the range.
Ranges are usually used with integers or `char`s:
```rust
let x = 'c';
match x {
'a' ... 'j' => println!("early ASCII letter"),
'k' ... 'z' => println!("late ASCII letter"),
_ => println!("something else"),
}
```
This prints `early ASCII letter`.
## ref and ref mut
Usually, when you match against a pattern, bindings are bound by value.
This means you'll end up moving the value out:
```rust,ignore
let name = Some(String::from("Bors"));
match name {
// name is moved here because of the binding to the `Some` value.
Some(inner_name) => println!("Found a name: {}", inner_name),
None => (),
}
// This line will fail to compile:
println!("name is: {:?}", name);
```
If you'd prefer to bind `name` by reference, use the `ref` keyword in order to
borrow the value instead:
```rust
let name = Some(String::from("Bors"));
match name {
// name is not moved here.
Some(ref inner_name) => println!("Found a name: {}", inner_name),
None => (),
}
// The match only took a reference to its data rather than moving it.
// This works:
println!("name is: {:?}", name);
```
And for a mutable reference, use `ref mut`:
```rust
let mut name = Some(String::from("Bors"));
match name {
// name is not moved here.
Some(ref mut inner_name) => *inner_name = String::from("Another name"),
None => (),
}
// The match only took a reference to its data rather than moving it.
// This works and prints the new value we gave it in the match statement:
println!("name is: {:?}", name);
```
## Ignoring bindings
We discussed using `_` as a whole pattern to ignore any value, but you can
also use `_` inside of another pattern to ignore just part of a value. This
usage of `_` will ignore the inner value of any `Some` value that is not a
`Some` with a `6` inside:
```rust
let x = Some(5);
match x {
Some(6) => println!("got a Some(6)"),
Some(_) => println!("got a Some and I don't care what's inside"),
None => (),
}
```
Its worth noting that using `_` never binds to the value, which means that the
value will not be moved:
```rust
let name = Some(String::from("Bors"));
match name {
// name is not moved here because the _ does not bind to the `Some` value.
Some(_) => println!("Found a name!"),
None => (),
}
// This works:
println!("name is: {:?}", name);
```
## Guards
You can introduce "match guards" with `if`. This adds an extra condition that
often uses a value that the pattern has bound to:
```rust
let x = Some(5);
match x {
Some(x) if x < 5 => println!("less than five: {}", x),
Some(x) => println!("{}", x),
None => (),
}
```
In this case, we bound the inner value of a `Some` to `x` and then "guarded" the
first match arm with an additional condition that `x` must be less than 5. In
this case, `Some(5)` does not have an inner value that is less than 5, so this
code will just print out `5`.
Whew! Thats a lot of different ways to match things. Let's cover one more place
you can use your newfound knowledge of patterns: `if let`.

View File

@ -18,7 +18,7 @@ case. With an `Option`, this isn't _too_ bad, but with a more complex enum,
adding `_ => {}` after processing just one variant doesn't feel great. We have
this boilerplate arm, and we have an extra level of indentation: the code that
does something with `x` is indented twice, rather than just once. We really want
a construct that says "Do something with this one case, I don't care about the
a construct that says "Do something with this one case; I don't care about the
others."
Enter `if let`:
@ -63,4 +63,4 @@ match expression {
```
In other words, it's the high-level construct we were originally looking for:
do something with a single pattern.
do something special with only one pattern.

View File

@ -1,241 +0,0 @@
# Patterns
We've mentioned 'patterns' a few times so far: they're used in `let` bindings,
in function arguments, and in the `match` expression. Patterns have a lot of
abilities, so in this section, we'll cover all of the different things they can
do. Any of these abilities work in any place where a pattern is used.
## Literals & _
You can match against literals directly, and `_` acts as an ‘any’ case:
```rust
let x = 1;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("anything"),
}
```
This prints `one`.
# Multiple patterns
You can match multiple patterns with `|`:
```rust
let x = 1;
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
_ => println!("anything"),
}
```
This prints `one or two`.
## ref and ref mut
Usually, when you match against a pattern, bindings are bound by value.
This means you'll end up moving the value out:
```rust,ignore
let name = Some(String::from("Bors"));
match name {
Some(name) => println!("Found a name: {}", name),
None => (),
}
// name is moved here. This line will fail to compile:
println!("name is: {:?}", name);
```
If you'd prefer to bind `name` by reference, use the `ref` keyword:
```rust
let name = Some(String::from("Bors"));
match name {
Some(ref name) => println!("Found a name: {}", name),
None => (),
}
// name is not moved here; the match only took a reference to its data rather
// than moving it. This will work:
println!("name is: {:?}", name);
```
And for a mutable reference, `ref mut`:
```rust
let mut name = Some(String::from("Bors"));
match name {
Some(ref mut name) => *name = String::from("Another name"),
None => (),
}
// name is not moved here; the match only took a reference to its data rather
// than moving it
```
## Destructuring
Patterns can be used to destructure structs and enums:
```rust
struct Point {
x: i32,
y: i32,
}
let origin = Point { x: 0, y: 0 };
let Point { x, y } = origin;
```
This brings an `x` and `y` binding into scope, matching the `x` and `y` of
`origin`. While it can be unusual in `let`, this is the same principle of
patterns in `match`:
```rust
struct Point {
x: i32,
y: i32,
}
let origin = Point { x: 0, y: 0 };
match origin {
Point { x, y } => { }, // x and y are bound here
}
```
## Shadowing
As with all bindings, anything bound by a pattern will shadow bindings
outside of the binding construct:
```rust
let x = Some(5);
match x {
Some(x) => { }, // x is an i32 here, not an Option<i32>
None => (),
}
```
## Ignoring bindings
We discussed using `_` as a whole pattern to ignore it above, but you can
also use `_` inside of another pattern to ignore just part of it:
```rust
let x = Some(5);
match x {
Some(_) => println!("got a Some and I don't care what's inside"),
None => (),
}
```
Or like this:
```rust
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, _, third, _, fifth) => println!("Some numbers: {}, {}, {}", first, third, fifth),
}
```
If you want, you can use `..` to ignore all of the parts you haven't defined:
```rust
struct Point {
x: i32,
y: i32,
z: i32,
}
let origin = Point { x: 0, y: 0, z: 0 };
match origin {
Point { x, .. } => { }, // y and z are ignored
}
```
## Ranges
You can match a range of values with `...`:
```rust
let x = 5;
match x {
1 ... 5 => println!("one through five"),
_ => println!("something else"),
}
```
Ranges are usually used with integers or `char`s:
```rust
fn main() {
let x = 'c';
match x {
'a' ... 'j' => println!("early ASCII letter"),
'k' ... 'z' => println!("late ASCII letter"),
_ => println!("something else"),
}
}
```
## Guards
You can introduce ‘match guards’ with `if`:
```rust
let x = Some(5);
match x {
Some(x) if x < 5 => println!("less than five: {}", x),
Some(x) => println!("{}", x),
None => (),
}
```
If you’re using if with multiple patterns, the if applies to both sides:
```rust
let x = 4;
let y = false;
match x {
4 | 5 if y => println!("yes"),
_ => println!("no"),
}
```
This prints `no`, because the if applies to the whole of `4 | 5`, and not to only
the `5`. In other words, the precedence of if behaves like this:
```text
(4 | 5) if y => ...
```
not this:
```text
4 | (5 if y) => ...
```
## Bindings
You can bind values to names with `@`: