Skip to content

Commit

Permalink
Propagate tech review edits to ch06 src
Browse files Browse the repository at this point in the history
  • Loading branch information
carols10cents committed May 26, 2022
1 parent 5f7f99c commit c76f1b4
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
fn main() {
// ANCHOR: here
let some_number = Some(5);
let some_string = Some("a string");
let some_char = Some('e');

let absent_number: Option<i32> = None;
// ANCHOR_END: here
Expand Down
4 changes: 0 additions & 4 deletions src/ch06-00-enums.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,3 @@ how pattern matching in the `match` expression makes it easy to run different
code for different values of an enum. Finally, we’ll cover how the `if let`
construct is another convenient and concise idiom available to handle enums in
your code.

Enums are a feature in many languages, but their capabilities differ in each
language. Rust’s enums are most similar to *algebraic data types* in functional
languages, such as F#, OCaml, and Haskell.
37 changes: 22 additions & 15 deletions src/ch06-01-defining-an-enum.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
## Defining an Enum

Enums are a way of defining custom data types in a different way than you do
with structs. Let’s look at a situation we might want to express in code and
see why enums are useful and more appropriate than structs in this case. Say we
need to work with IP addresses. Currently, two major standards are used for IP
addresses: version four and version six. Because these are the only
possibilities for an IP address that our program will come across, we can
*enumerate* all possible variants, which is where enumeration gets its name.
Where structs give you a way of grouping together related fields and data, like
a `Rectangle` with its `width` and `height`, enums give you a way of saying a
value is one of a possible set of values. For example, we may want to say that
`Rectangle` is one of a set of possible shapes that also includes `Circle` and
`Triangle`. To do this, Rust allows us to encode these possibilities as an enum.

Let’s look at a situation we might want to express in code and see why enums
are useful and more appropriate than structs in this case. Say we need to work
with IP addresses. Currently, two major standards are used for IP addresses:
version four and version six. Because these are the only possibilities for an
IP address that our program will come across, we can *enumerate* all possible
variants, which is where enumeration gets its name.

Any IP address can be either a version four or a version six address, but not
both at the same time. That property of IP addresses makes the enum data
Expand Down Expand Up @@ -183,12 +188,14 @@ useful: `Option`.

This section explores a case study of `Option`, which is another enum defined
by the standard library. The `Option` type encodes the very common scenario in
which a value could be something or it could be nothing. For example, if you
request the first of a list containing items, you would get a value. If you
request the first item of an empty list, you would get nothing. Expressing this
concept in terms of the type system means the compiler can check whether you’ve
handled all the cases you should be handling; this functionality can prevent
bugs that are extremely common in other programming languages.
which a value could be something or it could be nothing.

For example, if you request the first of a list containing items, you would get
a value. If you request the first item of an empty list, you would get nothing.
Expressing this concept in terms of the type system means the compiler can
check whether you’ve handled all the cases you should be handling; this
functionality can prevent bugs that are extremely common in other programming
languages.

Programming language design is often thought of in terms of which features you
include, but the features you exclude are important too. Rust doesn’t have the
Expand Down Expand Up @@ -246,8 +253,8 @@ types and string types:
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-06-option-examples/src/main.rs:here}}
```

The type of `some_number` is `Option<i32>`. The type of `some_string` is
`Option<&str>`, which is a different type. Rust can infer these types because
The type of `some_number` is `Option<i32>`. The type of `some_char` is
`Option<char>`, which is a different type. Rust can infer these types because
we’ve specified a value inside the `Some` variant. For `absent_number`, Rust
requires us to annotate the overall `Option` type: the compiler can’t infer the
type that the corresponding `Some` variant will hold by looking only at a
Expand Down
37 changes: 20 additions & 17 deletions src/ch06-02-match.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ down a track with variously sized holes along it, and each coin falls through
the first hole it encounters that it fits into. In the same way, values go
through each pattern in a `match`, and at the first pattern the value “fits,”
the value falls into the associated code block to be used during execution.

Speaking of coins, let’s use them as an example using `match`! We can write a
function that takes an unknown United States coin and, in a similar way as the
counting machine, determines which coin it is and return its value in cents, as
Expand Down Expand Up @@ -50,9 +51,10 @@ entire `match` expression.

We don’t typically use curly brackets if the match arm code is short, as it is
in Listing 6-3 where each arm just returns a value. If you want to run multiple
lines of code in a match arm, you must use curly brackets. For example, the
following code prints “Lucky penny!” every time the method is called with a
`Coin::Penny`, but still returns the last value of the block, `1`:
lines of code in a match arm, you must use curly brackets, and the comma
following the arm is then optional. For example, the following code prints
“Lucky penny!” every time the method is called with a `Coin::Penny`, but still
returns the last value of the block, `1`:

```rust
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-08-match-arm-multiple-lines/src/main.rs:here}}
Expand Down Expand Up @@ -161,8 +163,9 @@ consistently a user favorite.

### Matches Are Exhaustive

There’s one other aspect of `match` we need to discuss. Consider this version
of our `plus_one` function that has a bug and won’t compile:
There’s one other aspect of `match` we need to discuss: the arms’ patterns must
cover all possibilities. Consider this version of our `plus_one` function,
which has a bug and won’t compile:

```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/src/main.rs:here}}
Expand Down Expand Up @@ -208,17 +211,17 @@ This code compiles, even though we haven’t listed all the possible values a
`u8` can have, because the last pattern will match all values not specifically
listed. This catch-all pattern meets the requirement that `match` must be
exhaustive. Note that we have to put the catch-all arm last because the
patterns are evaluated in order. Rust will warn us if we add arms after a
catch-all because those later arms would never match!
patterns are evaluated in order. If we put the catch-all arm earlier, the other
arms would never run, so Rust will warn us if we add arms after a catch-all!

Rust also has a pattern we can use when we don’t want to use the value in the
catch-all pattern: `_`, which is a special pattern that matches any value and
does not bind to that value. This tells Rust we aren’t going to use the value,
so Rust won’t warn us about an unused variable.
Rust also has a pattern we can use when we want a catch-all but don’t want to
*use* the value in the catch-all pattern: `_` is a special pattern that matches
any value and does not bind to that value. This tells Rust we aren’t going to
use the value, so Rust won’t warn us about an unused variable.

Let’s change the rules of the game to be that if you roll anything other than
a 3 or a 7, you must roll again. We don’t need to use the value in that case,
so we can change our code to use `_` instead of the variable named `other`:
Let’s change the rules of the game: now, if you roll anything other than a 3 or
a 7, you must roll again. We no longer need to use the catch-all value, so we
can change our code to use `_` instead of the variable named `other`:

```rust
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/src/main.rs:here}}
Expand All @@ -227,9 +230,9 @@ so we can change our code to use `_` instead of the variable named `other`:
This example also meets the exhaustiveness requirement because we’re explicitly
ignoring all other values in the last arm; we haven’t forgotten anything.

If we change the rules of the game one more time, so that nothing else happens
on your turn if you roll anything other than a 3 or a 7, we can express that
by using the unit value (the empty tuple type we mentioned in [“The Tuple
Finally, we’ll change the rules of the game one more time, so that nothing else
happens on your turn if you roll anything other than a 3 or a 7. We can express
that by using the unit value (the empty tuple type we mentioned in [“The Tuple
Type”][tuples]<!-- ignore --> section) as the code that goes with the `_` arm:

```rust
Expand Down

0 comments on commit c76f1b4

Please sign in to comment.