From 7027c996c9dd92ca771636ba247657d0c18ed7bc Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 27 Jun 2016 19:37:10 -0600 Subject: [PATCH 01/32] Change type from u32 to u8 to match IPv4 spec Each segment of an ipv4 address can only be 0-255, so each of the segments only need to be u8s. If, however, this was done to not have to explain the difference between u32 and u8, or if this would be distracting from the point about enums trying to be made here, I would be fine reverting this change. --- src/ch06-01-enums.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch06-01-enums.md b/src/ch06-01-enums.md index 8778cdb..8682fb2 100644 --- a/src/ch06-01-enums.md +++ b/src/ch06-01-enums.md @@ -82,12 +82,12 @@ 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. 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, we’d 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), } From 7470b4c17e65a51a974e47ac138edb4163152e7f Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 27 Jun 2016 20:08:13 -0600 Subject: [PATCH 02/32] Hide a newline in a code example with hidden code This looks nicer. Connects to #106. --- src/ch06-01-enums.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch06-01-enums.md b/src/ch06-01-enums.md index 8682fb2..3973ac0 100644 --- a/src/ch06-01-enums.md +++ b/src/ch06-01-enums.md @@ -28,7 +28,7 @@ We can create values of `IpAddrKind` like this: # V4, # V6, # } - +# let four = IpAddrKind::V4; let six = IpAddrKind::V6; ``` From 3b4efffe4d4ea176406c1d9f84f48f5bcb35301c Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 27 Jun 2016 20:09:11 -0600 Subject: [PATCH 03/32] Punctuation edits --- src/ch06-01-enums.md | 6 +++--- src/ch06-02-option.md | 2 +- src/ch06-03-match.md | 12 ++++++------ src/ch06-04-if-let.md | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ch06-01-enums.md b/src/ch06-01-enums.md index 3973ac0..ae8611f 100644 --- a/src/ch06-01-enums.md +++ b/src/ch06-01-enums.md @@ -16,8 +16,8 @@ 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 +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. @@ -37,7 +37,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 don’t have a way to store the actual data of the IP address, +address type, we don’t 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: diff --git a/src/ch06-02-option.md b/src/ch06-02-option.md index f9b0ce0..0761330 100644 --- a/src/ch06-02-option.md +++ b/src/ch06-02-option.md @@ -89,7 +89,7 @@ shows one of the big advantages of an `Option` type: if you have a type 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` 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`? The option type has a large number of methods that you can check out in [its documentation], and becoming diff --git a/src/ch06-03-match.md b/src/ch06-03-match.md index d3f2417..fdfaeb0 100644 --- a/src/ch06-03-match.md +++ b/src/ch06-03-match.md @@ -1,7 +1,7 @@ # 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 +compare a value against a series of patterns and then execute code based on how they compare. Remember the `Option` type from the previous section? Let's say that we want to write a function that takes an `Option`, and if there's a value inside, add one to it. @@ -66,10 +66,10 @@ 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. +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. So +`Some(6)` is our return value as well, which is exactly what we were trying +to accomplish. Now let's consider the second call. In this case, `x` is `None`. We enter the `match`, and compare to the first arm: @@ -111,7 +111,7 @@ 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 +pattern we forgot! This is referred to as being "exhaustive": we must exhaust every last option possible in order to be valid! This analysis isn't perfect, however. This will also error: diff --git a/src/ch06-04-if-let.md b/src/ch06-04-if-let.md index 25c5b11..e2ce402 100644 --- a/src/ch06-04-if-let.md +++ b/src/ch06-04-if-let.md @@ -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`: From e89ff36d59f3599c56b33890568e40ba7f93d7ad Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 27 Jun 2016 20:09:25 -0600 Subject: [PATCH 04/32] Phrasing edits --- src/ch06-01-enums.md | 2 +- src/ch06-03-match.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ch06-01-enums.md b/src/ch06-01-enums.md index ae8611f..a180c12 100644 --- a/src/ch06-01-enums.md +++ b/src/ch06-01-enums.md @@ -1,7 +1,7 @@ # Enums Next, let’s look at a feature of Rust that’s similar to structs, but also -different. Enumerations, or ‘enums’ as they’re more commonly referred to, +different. Enumerations, or ‘enums’ as they’re more commonly called, 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. Rust’s enums are most similar to enums in functional languages. diff --git a/src/ch06-03-match.md b/src/ch06-03-match.md index fdfaeb0..64585c9 100644 --- a/src/ch06-03-match.md +++ b/src/ch06-03-match.md @@ -156,7 +156,7 @@ match some_u8_value { } ``` -The `_` pattern matches anything at all, and so with it as the final pattern, +The `_` pattern matches anything at all, 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 @@ -178,5 +178,5 @@ the unit 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. From d6502d203f42a3952d1ac7aec9434afdb399a33e Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 27 Jun 2016 20:09:34 -0600 Subject: [PATCH 05/32] Spelling edits --- src/ch06-01-enums.md | 2 +- src/ch06-02-option.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch06-01-enums.md b/src/ch06-01-enums.md index a180c12..13b40e8 100644 --- a/src/ch06-01-enums.md +++ b/src/ch06-01-enums.md @@ -80,7 +80,7 @@ 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 struct, we’d be stuck. But enums deal with this case with ease: diff --git a/src/ch06-02-option.md b/src/ch06-02-option.md index 0761330..650e2b0 100644 --- a/src/ch06-02-option.md +++ b/src/ch06-02-option.md @@ -3,7 +3,7 @@ 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. -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. From b67b0522e8354b40372805ac90bea8cf4c54fa87 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 18:42:36 -0600 Subject: [PATCH 06/32] Have enums lead into Option rather than match Connects to #113. --- src/ch06-01-enums.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ch06-01-enums.md b/src/ch06-01-enums.md index 13b40e8..6becdb5 100644 --- a/src/ch06-01-enums.md +++ b/src/ch06-01-enums.md @@ -133,10 +133,8 @@ enum Message { * `Write` includes a single `String`. * `ChangeColor` includes three `i32`s. -We haven’t talked a lot about how to access the data inside an enum variant, -however. To do that, let’s move on to some new Rust syntax that’s especially -useful with enums: `match`. - +Let's look at another enum in the standard library that is very common and +useful: `Option`. From 4db3b220b068cbacc22f46043eb4ec069c3e25a8 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 18:43:42 -0600 Subject: [PATCH 07/32] The reader might not "have a handle on enums" here Especially since we're only a small part of the way through this section. --- src/ch06-02-option.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch06-02-option.md b/src/ch06-02-option.md index 650e2b0..243e058 100644 --- a/src/ch06-02-option.md +++ b/src/ch06-02-option.md @@ -1,7 +1,7 @@ # 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 thought of as which features you include, but it's also about which features you leave out. Rust does not have a feature From 2051794d2054b6b53b2ccc03acd649f047fc2ad3 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 18:49:40 -0600 Subject: [PATCH 08/32] Calling Option a type is a bit confusing imo I mean, it *is*, but we said we were going to cover Option because it was an enum, so it might be confusing to start calling it a type if the reader hasn't fully understood that enums are types yet. --- src/ch06-02-option.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ch06-02-option.md b/src/ch06-02-option.md index 243e058..88f08cf 100644 --- a/src/ch06-02-option.md +++ b/src/ch06-02-option.md @@ -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`, 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`, and it looks like this: ```rust enum Option { @@ -40,7 +40,7 @@ enum Option { } ``` -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::`. @@ -85,15 +85,15 @@ let sum = x + y; Intense! What this error message is trying to say is that Rust does not understand how to add an `Option` and a `T`. They're different types! This -shows one of the big advantages of an `Option` type: if you have a type that +shows one of the big advantages of an `Option`: 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` 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. -So, how _do_ you get a `T` from an `Option`? 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. +So, how _do_ you get a `T` from an `Option`? The `Option` 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 From b508f9c5e7f54da8115ede9eca4d0150251b4e16 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 18:53:27 -0600 Subject: [PATCH 09/32] Restore some leading-into-match text in the right spot I did like the lead-in to why we would want match that was at the end of the enum section that I took out because match wasn't the next section. Put it back in Option since match is the next section after Option. --- src/ch06-02-option.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ch06-02-option.md b/src/ch06-02-option.md index 88f08cf..d4383cf 100644 --- a/src/ch06-02-option.md +++ b/src/ch06-02-option.md @@ -98,4 +98,5 @@ 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`. From 59ed4640720e7d7a6f29196452836916e0ed24d0 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 18:57:01 -0600 Subject: [PATCH 10/32] Be more specific and detailed in a few places --- src/ch06-03-match.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/ch06-03-match.md b/src/ch06-03-match.md index 64585c9..16493ce 100644 --- a/src/ch06-03-match.md +++ b/src/ch06-03-match.md @@ -4,7 +4,8 @@ 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` type from the previous section? Let's say that we want to write a function that takes an `Option`, 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: @@ -71,15 +72,16 @@ function, the value of the `match` will be the value of the function. So `Some(6)` is our return value as well, which is exactly what we were trying to accomplish. -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 @@ -160,7 +162,8 @@ The `_` pattern matches anything at all, 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: +something for one, three, five, and seven but not print anything for any other +number: ```rust # let some_u8_value = 0u8; @@ -174,7 +177,8 @@ 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 2, 4, +6, 8, 9, etc. in order to say that we want to do nothing for all of those. ## More about patterns From 8059a9301d509f7862a1986196963b64187f7301 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 18:59:29 -0600 Subject: [PATCH 11/32] Clarify expression/condition/value usage in context of match Connects to #112. It gets a little confusing when we're talking about a lot of nested expressions. The patterns aren't really getting matched to the expression, they're matched to the resulting value of the expression. --- src/ch06-03-match.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ch06-03-match.md b/src/ch06-03-match.md index 16493ce..c118211 100644 --- a/src/ch06-03-match.md +++ b/src/ch06-03-match.md @@ -22,26 +22,26 @@ 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: +Let's break down the `match`! At a high-level, using `match` looks like this: ```text -match condition { +match expression { 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. +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 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. +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, and the rest of the patterns are not checked. +If that pattern doesn't match the value, 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: From 8f62f51e7465405732644b6a92704cca5a63a7ed Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 19:01:31 -0600 Subject: [PATCH 12/32] Make the verb tense consistent --- src/ch06-03-match.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch06-03-match.md b/src/ch06-03-match.md index c118211..1b433f9 100644 --- a/src/ch06-03-match.md +++ b/src/ch06-03-match.md @@ -84,8 +84,8 @@ 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. From e5a638b4c7e8aa53f02e698d37d50e1cf40dbb5c Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 19:01:40 -0600 Subject: [PATCH 13/32] Hard wrap at 80 chars --- src/ch06-01-enums.md | 12 ++++++------ src/ch06-03-match.md | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ch06-01-enums.md b/src/ch06-01-enums.md index 6becdb5..0b8d447 100644 --- a/src/ch06-01-enums.md +++ b/src/ch06-01-enums.md @@ -16,10 +16,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: @@ -97,8 +97,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 { diff --git a/src/ch06-03-match.md b/src/ch06-03-match.md index 1b433f9..b62df29 100644 --- a/src/ch06-03-match.md +++ b/src/ch06-03-match.md @@ -102,8 +102,8 @@ fn plus_one(x: Option) -> Option { } ``` -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] From 7dd27c66c245185a33a82b38a15fa50297c0a445 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 19:07:20 -0600 Subject: [PATCH 14/32] Annotate numeric types so the error message doesn't have _ I think having a better error message will be less confusing than the type annotations here. I think the type annotations might actually help because now it's clearer that `i8` is `T` in this case. Also this error message has changed. --- src/ch06-02-option.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ch06-02-option.md b/src/ch06-02-option.md index d4383cf..7b6629e 100644 --- a/src/ch06-02-option.md +++ b/src/ch06-02-option.md @@ -67,8 +67,8 @@ In short, because `Option` 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 = 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>` is not implemented -for the type `_` [E0277] +error: the trait bound `i8: std::ops::Add>` is not +satisfied [E0277] let sum = x + y; ^~~~~ From f6e536a1a29f62741b5cf2b75ad29b91a44da546 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 19:11:38 -0600 Subject: [PATCH 15/32] Reorder so patterns is after match like the lead-in says Fixes #113. --- src/SUMMARY.md | 4 ++-- src/{ch06-05-patterns.md => ch06-04-patterns.md} | 0 src/{ch06-04-if-let.md => ch06-05-if-let.md} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{ch06-05-patterns.md => ch06-04-patterns.md} (100%) rename src/{ch06-04-if-let.md => ch06-05-if-let.md} (100%) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index ced5985..237f915 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -29,8 +29,8 @@ - [Chapter 6 - 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) - [Chapter 7 - Crates & Modules]() diff --git a/src/ch06-05-patterns.md b/src/ch06-04-patterns.md similarity index 100% rename from src/ch06-05-patterns.md rename to src/ch06-04-patterns.md diff --git a/src/ch06-04-if-let.md b/src/ch06-05-if-let.md similarity index 100% rename from src/ch06-04-if-let.md rename to src/ch06-05-if-let.md From cefbd7f16dae111f6af7ff0d0afa8dfd823c018c Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 21:12:07 -0600 Subject: [PATCH 16/32] Remove some of the less-commonly-used pattern abilities Connects to #115. Not fixes, because I'm going to give some of these more motivation before I think we can say we've covered what a new rustacean *needs* to know. Connects to #114 because I removed the trailing off last section, but I do want to give this section a real ending. --- src/ch06-04-patterns.md | 58 +++-------------------------------------- 1 file changed, 4 insertions(+), 54 deletions(-) diff --git a/src/ch06-04-patterns.md b/src/ch06-04-patterns.md index d696477..8a8cab6 100644 --- a/src/ch06-04-patterns.md +++ b/src/ch06-04-patterns.md @@ -1,9 +1,9 @@ # 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. +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. ## Literals & _ @@ -84,52 +84,6 @@ match name { // 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 - None => (), -} -``` - ## Ignoring bindings We discussed using `_` as a whole pattern to ignore it above, but you can @@ -188,7 +142,7 @@ 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"), @@ -235,7 +189,3 @@ not this: ```text 4 | (5 if y) => ... ``` - -## Bindings - -You can bind values to names with `@`: From 97c870f7bb399cca85f7bf67754f5015754ef12b Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 21:20:48 -0600 Subject: [PATCH 17/32] Give the patterns section a better ending That leads into the next section like the other sections do. Closes #114. --- src/ch06-04-patterns.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ch06-04-patterns.md b/src/ch06-04-patterns.md index 8a8cab6..5c80a5c 100644 --- a/src/ch06-04-patterns.md +++ b/src/ch06-04-patterns.md @@ -189,3 +189,6 @@ not this: ```text 4 | (5 if y) => ... ``` + +Whew! That’s a lot of different ways to match things. Let's cover one more place +you can use your newfound knowledge of patterns: `if let`. From 418c62e03471a54b855462119426a8049c3974c1 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 21:41:44 -0600 Subject: [PATCH 18/32] Give multiple patterns and ranges more motivation and move them together I feel like these are useful for the same reasons, are very similar, and should therefore be discussed in quick succession. Connects to #115. --- src/ch06-04-patterns.md | 100 +++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 38 deletions(-) diff --git a/src/ch06-04-patterns.md b/src/ch06-04-patterns.md index 5c80a5c..59d88d2 100644 --- a/src/ch06-04-patterns.md +++ b/src/ch06-04-patterns.md @@ -5,38 +5,89 @@ 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. -## Literals & _ - -You can match against literals directly, and `_` acts as an ‘any’ case: +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"), - 2 => println!("two"), 3 => println!("three"), - _ => println!("anything"), + 5 => println!("five"), + 7 => println!("seven"), + _ => println!("anything else"), } ``` -This prints `one`. +This prints `one`. If we change `x` to have the value 4, this would print +`anything else`. # Multiple patterns -You can match multiple patterns with `|`: +What if we wanted to print the same thing for 1, 3, and 5? We could do: ```rust let x = 1; match x { - 1 | 2 => println!("one or two"), - 3 => println!("three"), - _ => println!("anything"), + 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"), } ``` -This prints `one or two`. +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! statement 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 @@ -124,33 +175,6 @@ match origin { } ``` -## 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`: From 1051a435049967dbaea916c4e750129c5cd4cc53 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 21:54:21 -0600 Subject: [PATCH 19/32] Clarify the code examples in the ref/ref mut patterns section Connects to #115. --- src/ch06-04-patterns.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/ch06-04-patterns.md b/src/ch06-04-patterns.md index 59d88d2..9161369 100644 --- a/src/ch06-04-patterns.md +++ b/src/ch06-04-patterns.md @@ -98,41 +98,46 @@ This means you'll end up moving the value out: let name = Some(String::from("Bors")); match name { - Some(name) => println!("Found a name: {}", name), + // name is moved here because of the binding to the `Some` value. + Some(inner_name) => println!("Found a name: {}", inner_name), None => (), } -// name is moved here. This line will fail to compile: +// This line will fail to compile: println!("name is: {:?}", name); ``` -If you'd prefer to bind `name` by reference, use the `ref` keyword: +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 { - Some(ref name) => println!("Found a name: {}", name), + // name is not moved here. + Some(ref inner_name) => println!("Found a name: {}", inner_name), None => (), } -// name is not moved here; the match only took a reference to its data rather -// than moving it. This will work: +// The match only took a reference to its data rather than moving it. +// This works: println!("name is: {:?}", name); ``` -And for a mutable reference, `ref mut`: +And for a mutable reference, use `ref mut`: ```rust let mut name = Some(String::from("Bors")); match name { - Some(ref mut name) => *name = String::from("Another name"), + // name is not moved here. + Some(ref mut inner_name) => *inner_name = String::from("Another name"), None => (), } -// name is not moved here; the match only took a reference to its data rather -// than moving it +// 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 From 9e292dfa6d6c1a0d14ace04f715fd076b17a80fc Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 21:56:06 -0600 Subject: [PATCH 20/32] Clarify and simplify using _ to ignore parts of bindings I feel like destructuring tuples and struct fields is less common. I do think it's worth pointing out that _ doesn't bind, though. Connects to #115. --- src/ch06-04-patterns.md | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/src/ch06-04-patterns.md b/src/ch06-04-patterns.md index 9161369..9253ef7 100644 --- a/src/ch06-04-patterns.md +++ b/src/ch06-04-patterns.md @@ -142,42 +142,35 @@ println!("name is: {:?}", name); ## 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: +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 => (), } ``` -Or like this: +It’s worth noting that using `_` never binds to the value, which means that the +value will not be moved: ```rust -let numbers = (2, 4, 8, 16, 32); +let name = Some(String::from("Bors")); -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, +match name { + // name is not moved here because the _ does not bind to the `Some` value. + Some(_) => println!("Found a name!"), + None => (), } -let origin = Point { x: 0, y: 0, z: 0 }; - -match origin { - Point { x, .. } => { }, // y and z are ignored -} +// This works: +println!("name is: {:?}", name); ``` ## Guards From b113cc9014fded8d7a87f6a2672fcf8bb371c6ec Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 21:58:00 -0600 Subject: [PATCH 21/32] Simplify and clarify match guards I feel like the precedence issues are a bit too nuanced and not worth spending time on. Match guards can be useful, though. Fixes #115 at this point, in my view. --- src/ch06-04-patterns.md | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/src/ch06-04-patterns.md b/src/ch06-04-patterns.md index 9253ef7..c89b6ff 100644 --- a/src/ch06-04-patterns.md +++ b/src/ch06-04-patterns.md @@ -175,7 +175,8 @@ println!("name is: {:?}", name); ## Guards -You can introduce ‘match guards’ with `if`: +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); @@ -187,30 +188,10 @@ match x { } ``` -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) => ... -``` +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! That’s a lot of different ways to match things. Let's cover one more place you can use your newfound knowledge of patterns: `if let`. From c7979df8b20d847e9fe844641ac764f2069577bc Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 22:06:24 -0600 Subject: [PATCH 22/32] Give more enum motivation in the intro paragraph Taking suggestions from @aturon. I like how this foreshadows why this chapter has sections on patterns. Connects to #106. --- src/ch06-01-enums.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ch06-01-enums.md b/src/ch06-01-enums.md index 0b8d447..7df718e 100644 --- a/src/ch06-01-enums.md +++ b/src/ch06-01-enums.md @@ -1,12 +1,13 @@ # Enums -Next, let’s look at a feature of Rust that’s similar to structs, but also -different. Enumerations, or ‘enums’ as they’re more commonly called, -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. Rust’s enums are -most similar to enums in functional languages. +Next, let’s 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. Rust’s enums +are most similar to "algebraic data types" in functional languages like F#, +OCaml, or Haskell. -Here’s an example of an enum: +Here’s an example of an enum definition: ```rust enum IpAddrKind { From b1d3ceb269ef79d03a7c131352280fb62039e79c Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 29 Jun 2016 22:10:22 -0600 Subject: [PATCH 23/32] Be less dogmatic about idiomatic Connects to #106. --- src/ch06-01-enums.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch06-01-enums.md b/src/ch06-01-enums.md index 7df718e..8af6b97 100644 --- a/src/ch06-01-enums.md +++ b/src/ch06-01-enums.md @@ -65,8 +65,8 @@ let loopback = IpAddr { ``` We’ve used a struct to bundle the two values together: now we keep the kind -with the value itself. This design isn’t bad, exactly, but it wouldn’t 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 { From b59a62e0e65bd306d1aeed4ebe872078ad71d851 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 30 Jun 2016 19:40:40 -0600 Subject: [PATCH 24/32] Compare enum syntax to struct syntax Closes #106. Thank you @aturon! --- src/ch06-01-enums.md | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/ch06-01-enums.md b/src/ch06-01-enums.md index 8af6b97..c229ae7 100644 --- a/src/ch06-01-enums.md +++ b/src/ch06-01-enums.md @@ -134,14 +134,21 @@ enum Message { * `Write` includes a single `String`. * `ChangeColor` includes three `i32`s. +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`. - - - - - - - - - From df9adca27d5ba308703de06ce7886e3728bd375d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 30 Jun 2016 19:46:31 -0600 Subject: [PATCH 25/32] Add a paragraph connecting Option to the $1B mistake Fixes #111. Thank you @aturon! --- src/ch06-02-option.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ch06-02-option.md b/src/ch06-02-option.md index 7b6629e..be8444c 100644 --- a/src/ch06-02-option.md +++ b/src/ch06-02-option.md @@ -91,6 +91,14 @@ exists. In other words, you have to convert an `Option` 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. +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`. +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`, 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`? The `Option` 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. From 5effbd5a93237dbe324e7f2456fe9bbe821a8402 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 30 Jun 2016 19:53:54 -0600 Subject: [PATCH 26/32] Skip match exhaustiveness not being perfect Connects to #112. Thank you @aturon! --- src/ch06-03-match.md | 58 +++++++------------------------------------- 1 file changed, 9 insertions(+), 49 deletions(-) diff --git a/src/ch06-03-match.md b/src/ch06-03-match.md index b62df29..83ea712 100644 --- a/src/ch06-03-match.md +++ b/src/ch06-03-match.md @@ -116,54 +116,13 @@ 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! -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, `_`: - -```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, 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 for one, three, five, and seven but not print anything for any other -number: +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; @@ -177,8 +136,9 @@ match some_u8_value { ``` The `_` pattern will match all the other cases, and `()` will do nothing, it's -the unit value. This way, we don't have to list individual match arms for 2, 4, -6, 8, 9, etc. in order to say that we want to do nothing for all of those. +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 From f42b92d769832f3c0d139cba7c3c375efad0c5a8 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 30 Jun 2016 20:10:44 -0600 Subject: [PATCH 27/32] Clarify some points about the code in match arms - Change the example to have an arm with multiple lines - Explain the deal with multiple lines - Emphasize that these are expressions Connects to #112. Thank you @aturon! --- src/ch06-03-match.md | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/ch06-03-match.md b/src/ch06-03-match.md index 83ea712..bbccc56 100644 --- a/src/ch06-03-match.md +++ b/src/ch06-03-match.md @@ -13,7 +13,10 @@ This function is very easy to write, thanks to `match`. It looks like this: fn plus_one(x: Option) -> Option { match x { None => None, - Some(i) => Some(i + 1), + Some(i) => { + let h = i + 1; + Some(h) + }, } } @@ -40,8 +43,15 @@ 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 resulting value against the pattern of each arm, in order. If a pattern matches the value, the code associated -with that pattern is executed, and the rest of the patterns are not checked. -If that pattern doesn't match the value, execution continues to the next arm. +with that pattern is executed. If that pattern doesn't match the value, +execution continues to the next arm. + +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. If the match arm code is short, as +in the `None` case above, curly braces typically aren't used. If you want to +have multiple lines of code within a `match` arm, you can use curly braces as +in the `Some` case. 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: @@ -53,7 +63,10 @@ None => None, Does `Some(5)` match `None`? No, it's the wrong variant. So let's continue. ```text -Some(i) => Some(i + 1), +Some(i) => { + let h = i + 1; + Some(h) +}, ``` Does `Some(5)` match `Some(i)`? Why yes it does! We have the same variant. But @@ -61,9 +74,15 @@ 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`. -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. +With this arm, the code portion is: + +```text +let h = i + 1; +Some(h) +``` + +So we do exactly that: we take `i`, which is `5`, add one to it and bind that +to `h`, then create a new `Some` value with the value of `h` 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 @@ -97,7 +116,10 @@ of `plus_one()`: ```rust,ignore fn plus_one(x: Option) -> Option { match x { - Some(i) => Some(i + 1), + Some(i) => { + let h = i + 1; + Some(h) + }, } } ``` @@ -108,7 +130,10 @@ catch. If we try to compile this code, we'll get an error: ```text error: non-exhaustive patterns: `None` not covered [E0004] match x { - Some(i) => Some(i + 1), + Some(i) => { + let h = i + 1; + Some(h) + }, } ``` From 30604a5fe8265dbeb8cc2b00b0a50ed16e676006 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 30 Jun 2016 20:21:18 -0600 Subject: [PATCH 28/32] Connect exhaustiveness checking to $1B mistake Connects to #112. Thanks @aturon! --- src/ch06-03-match.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ch06-03-match.md b/src/ch06-03-match.md index bbccc56..8a89889 100644 --- a/src/ch06-03-match.md +++ b/src/ch06-03-match.md @@ -139,7 +139,11 @@ 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! +every last option possible in order to be valid. Especially in the case of +`Option`, 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. ## The _ placeholder From 957eb7e5175e74362e56b52043d241132982d097 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 1 Jul 2016 12:58:13 -0600 Subject: [PATCH 29/32] Show the variable declaration in this example I think the variable declaration makes this clearer, in case the reader wants to copy-paste and play with it. --- src/ch06-03-match.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch06-03-match.md b/src/ch06-03-match.md index 8a89889..cb0f6ad 100644 --- a/src/ch06-03-match.md +++ b/src/ch06-03-match.md @@ -154,7 +154,7 @@ 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; +let some_u8_value = 0u8; match some_u8_value { 1 => println!("one"), 3 => println!("three"), From 622b4ac83f1bef66ea212391aa963f22d7fbd587 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 1 Jul 2016 13:01:00 -0600 Subject: [PATCH 30/32] Clarify talking about println! in prose - Make code - Avoid expression/statement confusion by not saying either of those --- src/ch06-04-patterns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch06-04-patterns.md b/src/ch06-04-patterns.md index c89b6ff..1337529 100644 --- a/src/ch06-04-patterns.md +++ b/src/ch06-04-patterns.md @@ -56,7 +56,7 @@ match x { ``` This match statement has the same functionality as the previous one, but we only -had to write the common println! statement once! +had to write the common `println!` once! ## Ranges From 25903564755cf37534f61d990d08f232176f55d3 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 1 Jul 2016 18:56:08 -0600 Subject: [PATCH 31/32] Clear up the last sentence of the if let section a bit --- src/ch06-05-if-let.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch06-05-if-let.md b/src/ch06-05-if-let.md index e2ce402..0efe560 100644 --- a/src/ch06-05-if-let.md +++ b/src/ch06-05-if-let.md @@ -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. From 7ac400d5608d22160e5bf0b5d8e3d87a63dbb61d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 1 Jul 2016 20:48:44 -0600 Subject: [PATCH 32/32] Rework the match example to be about coin sorting Fixes #115. Thanks to some brainstorming with @pindell-matt and @selfup at Turing, we've got what I think is a better analogy of a coin sorting machine! --- src/ch06-03-match.md | 207 +++++++++++++++++++++++++++++++------------ 1 file changed, 152 insertions(+), 55 deletions(-) diff --git a/src/ch06-03-match.md b/src/ch06-03-match.md index cb0f6ad..f757574 100644 --- a/src/ch06-03-match.md +++ b/src/ch06-03-match.md @@ -2,27 +2,35 @@ 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` type from the previous section? -Let's say that we want to write a function that takes an `Option`, and -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. +how they compare. -This function is very easy to write, thanks to `match`. It looks like this: +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 -fn plus_one(x: Option) -> Option { - match x { - None => None, - Some(i) => { - let h = i + 1; - Some(h) - }, - } +enum Coin { + Dime, + Penny, + Nickel, + Quarter, } -let five = Some(5); -let six = plus_one(five); -let none = plus_one(None); +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: @@ -39,19 +47,134 @@ 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 two +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. +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. If the match arm code is short, as -in the `None` case above, curly braces typically aren't used. If you want to -have multiple lines of code within a `match` arm, you can use curly braces as -in the `Some` case. +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` 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`, and +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: + +```rust +fn plus_one(x: Option) -> Option { + match x { + None => None, + Some(i) => Some(i + 1), + } +} + +let five = Some(5); +let six = plus_one(five); +let none = plus_one(None); +``` 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: @@ -63,33 +186,13 @@ None => None, Does `Some(5)` match `None`? No, it's the wrong variant. So let's continue. ```text -Some(i) => { - let h = i + 1; - Some(h) -}, +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`. - -With this arm, the code portion is: - -```text -let h = i + 1; -Some(h) -``` - -So we do exactly that: we take `i`, which is `5`, add one to it and bind that -to `h`, then create a new `Some` value with the value of `h` 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. So -`Some(6)` is our return value as well, which is exactly what we were trying -to accomplish. +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. 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: @@ -116,10 +219,7 @@ of `plus_one()`: ```rust,ignore fn plus_one(x: Option) -> Option { match x { - Some(i) => { - let h = i + 1; - Some(h) - }, + Some(i) => Some(i + 1), } } ``` @@ -130,10 +230,7 @@ catch. If we try to compile this code, we'll get an error: ```text error: non-exhaustive patterns: `None` not covered [E0004] match x { - Some(i) => { - let h = i + 1; - Some(h) - }, + Some(i) => Some(i + 1), } ```