From 7027c996c9dd92ca771636ba247657d0c18ed7bc Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 27 Jun 2016 19:37:10 -0600 Subject: [PATCH 001/204] 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 8778cdbca6..8682fb29d9 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 002/204] 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 8682fb29d9..3973ac090a 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 003/204] 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 3973ac090a..ae8611fbea 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 f9b0ce0ba7..0761330af6 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 d3f2417253..fdfaeb046f 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 25c5b11e85..e2ce4022e2 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 004/204] 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 ae8611fbea..a180c12f28 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 fdfaeb046f..64585c93ce 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 005/204] 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 a180c12f28..13b40e83d1 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 0761330af6..650e2b0042 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 006/204] 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 13b40e83d1..6becdb5079 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 007/204] 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 650e2b0042..243e058187 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 008/204] 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 243e058187..88f08cf324 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 009/204] 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 88f08cf324..d4383cf3f4 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 010/204] 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 64585c93ce..16493ce375 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 011/204] 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 16493ce375..c118211d24 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 012/204] 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 c118211d24..1b433f9a8b 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 013/204] 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 6becdb5079..0b8d447cb3 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 1b433f9a8b..b62df29f61 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 014/204] 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 d4383cf3f4..7b6629e5be 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 015/204] 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 ced5985f68..237f915715 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 016/204] 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 d6964778cf..8a8cab66e8 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 017/204] 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 8a8cab66e8..5c80a5cedc 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 018/204] 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 5c80a5cedc..59d88d2fb1 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"), +} +``` + +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 or two`. +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 019/204] 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 59d88d2fb1..916136982f 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 020/204] 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 916136982f..9253ef7694 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); - -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: +let name = Some(String::from("Bors")); -```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 021/204] 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 9253ef7694..c89b6ff373 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 022/204] 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 | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ch06-01-enums.md b/src/ch06-01-enums.md index 0b8d447cb3..7df718eee2 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. - -Here’s an example of an enum: +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 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 023/204] 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 7df718eee2..8af6b97ab5 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 024/204] 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 8af6b97ab5..c229ae7ce8 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. -Let's look at another enum in the standard library that is very common and -useful: `Option`. - - - - - - - +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 025/204] 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 7b6629e5be..be8444cf1d 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 026/204] 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 b62df29f61..83ea712116 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 027/204] 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 83ea712116..bbccc56a68 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 028/204] 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 bbccc56a68..8a89889101 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 029/204] 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 8a89889101..cb0f6ad6de 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 030/204] 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 c89b6ff373..1337529473 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 031/204] 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 e2ce4022e2..0efe5605a7 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 032/204] 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 cb0f6ad6de..f75757407b 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,57 +47,152 @@ 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. -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: +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`: -```text -None => None, +```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, + } +} ``` -Does `Some(5)` match `None`? No, it's the wrong variant. So let's continue. +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: -```text -Some(i) => { - let h = i + 1; - Some(h) -}, +```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 + }, + } +} ``` -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`. +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); +``` -With this arm, the code portion is: +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: ```text -let h = i + 1; -Some(h) +None => None, ``` -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. +Does `Some(5)` match `None`? No, it's the wrong variant. So let's continue. + +```text +Some(i) => Some(i + 1), +``` -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), } ``` From b5064f0ce72dadb12d2b080f1e186541b755b7da Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 3 Jul 2016 14:46:08 -0400 Subject: [PATCH 033/204] Backport edits made to Up and Running section --- src/ch03-01-up-and-running.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ch03-01-up-and-running.md b/src/ch03-01-up-and-running.md index 0a7886b440..8b1bbba587 100644 --- a/src/ch03-01-up-and-running.md +++ b/src/ch03-01-up-and-running.md @@ -1,11 +1,11 @@ # Up and Running -We’ll start our journey with Rust by talking about the absolute basics — -concepts that appear in almost every programming language. Many programming -languages have lots in common at their core. None of the concepts presented are -unique to Rust, but we’ll cover Rust’s particular syntax and conventions around -these common concepts. +We’ll start our Rust journey by talking about the absolute basics, concepts +that appear in almost every programming language. Many programming languages +have much in common at their core. None of the concepts presented in this +chapter are unique to Rust, but we’ll discuss Rust’s particular syntax and +conventions concerning these common concepts. -If you want to skip this section, you can, but you may end up coming back later -to find out small details. These foundations will be in every single useful -Rust program, and learning them gives us a strong core to start from. +Specifically, we’ll be talking about variable bindings, functions, basic types, +comments, `if` statements, and looping. These foundations will be in every Rust +program, and learning them early will give you a strong core to start from. From e094c3bd4ea8a59d91d1486b1eed6ec52c04c48a Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 3 Jul 2016 14:49:44 -0400 Subject: [PATCH 034/204] Backport addition of Anatomy of a Rust Program section --- src/SUMMARY.md | 1 + src/ch03-02-anatomy-of-a-rust-program.md | 303 +++++++++++++++++++++++ 2 files changed, 304 insertions(+) create mode 100644 src/ch03-02-anatomy-of-a-rust-program.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index e5d428b065..1a1e68e98a 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -8,6 +8,7 @@ - [Tutorial]() - [Up and Running](ch03-01-up-and-running.md) + - [Anatomy of a Rust Program](ch03-02-anatomy-of-a-rust-program.md) - [Variable Bindings](ch03-02-variable-bindings.md) - [Functions](ch03-03-functions.md) - [Scalar Types](ch03-04-scalar-types.md) diff --git a/src/ch03-02-anatomy-of-a-rust-program.md b/src/ch03-02-anatomy-of-a-rust-program.md new file mode 100644 index 0000000000..ce63b4561a --- /dev/null +++ b/src/ch03-02-anatomy-of-a-rust-program.md @@ -0,0 +1,303 @@ +## Anatomy of a Rust Program + +The foundation of virtually every program is the ability to store and modify +data, but to create this data, you first have to create a program. Here, we'll +write some code that demonstrates how to begin a Rust program, how to bind a +variable, and how to print text to the terminal. + +### Keywords + + + +First, keep in mind that the Rust language has a set of *keywords* that have +been reserved for use by the language only. This means you cannot use these +words as names of variables or functions, for example. Most of these have +special meaning and we will be using them to do various things in our Rust +programs; a few have no current functionality associated but have been reserved +for functionality that might be in the Rust language in the future. + +The keywords are: + +* `abstract` +* `alignof` +* `as` +* `become` +* `box` +* `break` +* `const` +* `continue` +* `crate` +* `do` +* `else` +* `enum` +* `extern` +* `false` +* `final` +* `fn` +* `for` +* `if` +* `impl` +* `in` +* `let` +* `loop` +* `macro` +* `match` +* `mod` +* `move` +* `mut` +* `offsetof` +* `override` +* `priv` +* `proc` +* `pub` +* `pure` +* `ref` +* `return` +* `Self` +* `self` +* `sizeof` +* `static` +* `struct` +* `super` +* `trait` +* `true` +* `type` +* `typeof` +* `unsafe` +* `unsized` +* `use` +* `virtual` +* `where` +* `while` +* `yield` + +### A Simple Program that Binds a Variable + +Let’s start with a short example that binds a value to a variable, and then +uses that in a sentence that we'll print to the screen. First, we’ll generate a +new project with Cargo. Open a terminal, and navigate to the directory you want +to store your projects in. From there, generate a new project: + +```bash +$ cargo new --bin bindings +$ cd bindings +``` + +This creates a new project called `bindings` and sets up our *Cargo.toml* and +*src/main.rs* files. As we saw in Chapter XX, Cargo will generate these files +and create a little "hello world" program like this: + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +Open *src/main.rs* and replace its code with the following: + +```rust +fn main() { + let x = 5; + + println!("The value of x is: {}", x); +} +``` + +This is the full program for our example. Enter the `run` command now to to see +it working: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) + Running `target/debug/bindings` +The value of x is: 5 +``` + +If you get an error instead of this output, double check that you've copied the +program exactly as written, and then try again. Now let’s break this program +down, line by line. + +#### Starting a Program with the main() Function + +Most Rust programs open with the same first line as this one from our example +program: + + +```rust,ignore +fn main() { +``` + +The `main()` function is the entry point of every Rust program. It doesn’t have +to be at the very beginning of our source code, but it will be the first bit of code that +runs when we execute our program. We’ll talk more about functions in the next +section, but for now, just know that ```main()``` is where our program begins. +The opening curly brace (`{`) indicates the start of the function’s body. + +#### Binding a Variable with `let` + +Inside the function body, we added the following: + +```rust,ignore + let x = 5; +``` + +This is a `let` statement, and it binds the value `5` to the variable `x`. +Basic `let` statements take the following form: + +```text +let NAME = EXPRESSION; +``` + +A `let` statement first evaluates the `EXPRESSION`, and then binds the +resulting value to `NAME` to give us a variable to use later in the program. +Notice the semicolon at the end of the statement, too. As in many other +programming languages, statements in Rust must end with a semicolon. + +In this simple example, the expression already is a value, but we could achieve +the same result like this: + +```rust +let x = 2 + 3; +``` + +The expression `2 + 3` would evaluate to `5`, which would in turn be stored in +the `x` variable binding. + +More generally, `let` statements take the form: + +```text +let PATTERN = EXPRESSION; +``` + +*Patterns* are part of the ‘pattern matching’ feature of Rust. If you have +worked with regular expressions, you can think of patterns like a regular +expression that works on values in your program instead of characters in text. +A name like `x` is a particularly humble form of pattern; it will always match +and gets all the parts of the expression as its value. Patterns are a big part +of Rust, and we’ll see more complex and powerful patterns as we go along. + + +#### Printing to the Screen with a Macro + +The next line of our program is: + +```rust,ignore + println!("The value of x is: {}", x); +``` + +The `println!` command is a *macro* that prints the text passed to it to the +screen. Macros are indicated with the `!` character at the end of their name. +In Chapter , you'll learn more about the details of macros and how to +write macros yourself, but for now we'll just be using macros provided by the +standard Rust library. + +Macros can add new syntax to the language to enable convenient code reuse. +Using a macro may look similar to calling a function, but they do have +different capabilities. The `!` is a reminder that calling a macro may look +slightly unusual. For example, the "Hello, world!" program that `cargo new` +generated for us called the `println!` macro with one argument (the string +`"Hello, world!"`). Here, we are calling it with two arguments (the string +`"The value of x is: {}"` and `x`). Functions in Rust must always be called +with the same number of arguments that their definition specifies, but macros +have different rules that allow them to take different numbers of arguments. + + + +The `println!` macro only requires one argument: a format string. You can add +optional arguments inside this format string by using the special text `{}`. +Each instance of `{}` corresponds to an additional argument. Here’s an example: + +```rust +let x = 2 + 3; +let y = x + 5; + +println!("The value of x is {}, and the value of y is {}", x, y); +``` + +If you were to run a program containing these statements, it would print the +following: + +```text +The value of x is 5, and the value of y is 10 +``` + +Think of `{}` as little crab pincers, holding a value in place. The first `{}` +holds the first value after the format string, the second set holds the second +value, and so on. The `{}` placeholder has a number of more advanced formatting +options that we’ll discuss later. + +After the `println!` macro, we match the opening curly brace that declared the +`main()` function with a closing curly brace to declare the end of the function: + +```rust,ignore +} +``` + +And of course, when we run the program, our output is: + +```text +The value of x is: 5 +``` + +With this simple program, you've created your first variable and used your +first Rust macro. That makes you a Rust programmer. Welcome! Now that you've +seen the basics, let's explore variable bindings further. From 8bf85b6a580d399234df0935a7c89850c9c895d4 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 3 Jul 2016 14:51:52 -0400 Subject: [PATCH 035/204] Backport changes to Variable Bindings in Detail section --- src/SUMMARY.md | 2 +- src/ch03-02-variable-bindings.md | 638 --------------------- src/ch03-03-variable-bindings-in-detail.md | 572 ++++++++++++++++++ 3 files changed, 573 insertions(+), 639 deletions(-) delete mode 100644 src/ch03-02-variable-bindings.md create mode 100644 src/ch03-03-variable-bindings-in-detail.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 1a1e68e98a..53de81193c 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -9,7 +9,7 @@ - [Up and Running](ch03-01-up-and-running.md) - [Anatomy of a Rust Program](ch03-02-anatomy-of-a-rust-program.md) - - [Variable Bindings](ch03-02-variable-bindings.md) + - [Variable Bindings in Detail](ch03-03-variable-bindings-in-detail.md) - [Functions](ch03-03-functions.md) - [Scalar Types](ch03-04-scalar-types.md) - [Compound Types](ch03-05-compound-types.md) diff --git a/src/ch03-02-variable-bindings.md b/src/ch03-02-variable-bindings.md deleted file mode 100644 index d9b8d0fc06..0000000000 --- a/src/ch03-02-variable-bindings.md +++ /dev/null @@ -1,638 +0,0 @@ -# Variable Bindings - -The foundation of virtually every program is the ability to store and modify -data. Rust programs are no different. Let’s start with a short example. - -## The basics of bindings - -First, we’ll generate a new project with Cargo. Open a terminal, and navigate -to the directory where you’d like to keep your projects. From there, let’s -generate a new project: - -```bash -$ cargo new --bin bindings -$ cd bindings -``` - -This creates a new project, ‘bindings’, and sets up our `Cargo.toml` and -`src/main.rs` files. As we saw in “Hello, World!”, Cargo will generate these -files and create a little ‘hello world’ program for us: - -```rust -fn main() { - println!("Hello, world!"); -} -``` - -Let’s replace that program with this one: - -```rust -fn main() { - let x = 5; - - println!("The value of x is: {}", x); -} -``` - -And finally, run it: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -``` - -If you see an error instead, double check that you have copied the program -exactly as written. Let’s break this down, line by line. - -```rust,ignore -fn main() { -``` - -The `main()` function is the entry point of every Rust program. We’ll talk more -about functions in the next section, but for now, all we need to know is that -this is where our program begins. The opening curly brace, `{`, indicates the -start of the function’s body. - -```rust,ignore - let x = 5; -``` - -This is our first ‘variable binding’, which we create with a ‘`let` statement’. - -This `let` statement has this form: - -```text -let NAME = EXPRESSION; -``` - -A `let` statement first evaluates the `EXPRESSION`, and then binds the -resulting value to `NAME` so that it can be referred to later in the program. -In our simple example, the expression was already a value, 5, but we could -achieve the same effect with: - -```rust -let x = 2 + 3; -``` - -In general, `let` statements work with patterns; a name is a particularly -humble form of pattern. Patterns are a big part of Rust, we’ll see more complex -and powerful patterns as we go along. - -Before we do that, though, let’s finish investigating this example. Here’s the -next line: - -```rust,ignore - println!("The value of x is: {}", x); -``` - -The `println!` macro prints text to the screen. We can tell that it’s a macro -due to the `!`. We won’t learn how to write macros until much later in the -book, but we’ll use macros provided by the standard library throughout. Every -time you see a `!`, remember that it signifies a macro. Macros can add new -syntax to the language, and the `!` is a reminder that things may look slightly -unusual. - -`println!`, specifically, has one required argument, a ‘format string’, and -zero or more optional arguments. The format string can contain the special text -`{}`. Each instance of `{}` corresponds to an additional argument. Here’s an -example: - -```rust -let x = 2 + 3; -let y = x + 5; -println!("The value of x is {}, and the value of y is {}", x, y); -``` - -You can think of `{}` as little crab pincers, holding the value in place. This -placeholder has a number of more advanced formatting options that we’ll discuss -later. - -```rust,ignore -} -``` - -Finally, a closing curly brace matches up with the opening curly brace that -declared the `main()` function, and declares its end. - -This explains our output: - -```text -The value of x is: 5 -``` - -We assign `5` to a binding, `x`, and then print it to the screen with -`println!`. - -## Multiple binding - -Let’s try a more complex pattern. Change our example program to this: - -```rust -fn main() { - let (x, y) = (5, 6); - - println!("The value of x is: {}", x); - println!("The value of y is: {}", y); -} -``` - -And run it with `cargo run`: - -```text -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -The value of y is: 6 -``` - -We’ve created two bindings with one `let`! Here’s our pattern: - -```text -(x, y) -``` - -And here’s the value: - -```text -(5, 6) -``` - -As you can see, the two line up visually, and so `let` binds `5` to `x` and `6` -to `y`. We could have used two `let` statements as well: - -```rust -fn main() { - let x = 5; - let y = 6; -} -``` - -In simple cases like this, two `let`s may be clearer, but in others, creating -multiple bindings at once is nice. As we become more proficient in Rust, we’ll -figure out which style is better, but it’s mostly a judgement call. - -## Type annotations - -You may have noticed that we didn’t declare the type of `x` or `y` in our -previous examples. Rust is a *statically typed* language, which means that at -compile time, we must know the types of all bindings. But annotating every -single binding with a type can feel like busywork, and make code noisy. To -solve this issue, Rust uses ‘type inference’, meaning that it attempts to infer -the types of your bindings. - -The primary way that the type is inferred is by looking at how it is used. -Let’s look at the example again: - -```rust -fn main() { - let x = 5; -} -``` - -When we bind `x` to `5`, the compiler knows that `x` should be a numeric type. -Without any other information, it defaults to `i32`, a thirty-two bit integer -type. We’ll talk more about Rust’s basic types in section 3.3. - -Here’s what a `let` statement with a ‘type annotation’ looks like: - -```rust -fn main() { - let x: i32 = 5; -} -``` - -We can add a colon, followed by the type name. Here’s the structure of a `let` -statement with a type annotation: - -```text -let PATTERN: TYPE = VALUE; -``` - -Note that the colon and the `TYPE` go _after_ the `PATTERN`, not in the pattern -itself. As an example, here’s our more complex pattern with two bindings: - -```rust -fn main() { - let (x, y): (i32, i32) = (5, 6); -} -``` - -Just like we match up the `VALUE` with the `PATTERN`, we match up the `TYPE` -with the `PATTERN`. - -## Delayed Initialization - -We do not have to provide bindings with an initial value, and can assign it -later. Try this program: - -```rust -fn main() { - let x; - - x = 5; - - println!("The value of x is: {}", x); -} -``` - -And run it with `cargo run`: - -```text -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -``` - -It’s all good. This raises a question, though: what if we try to print out a -binding before we declare a value? Here’s a program that demonstrates this -question: - -```rust,ignore -fn main() { - let x; - - println!("The value of x is: {}", x); - - x = 5; -} -``` - -We can find out the answer with `cargo run`: - -```text - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x` [E0381] -src/main.rs:4 println!(“The value of x is: {}”, x); - ^ -:2:25: 2:56 note: in this expansion of format_args! -:3:1: 3:54 note: in this expansion of print! (defined in ) -src/main.rs:4:5: 4:42 note: in this expansion of println! (defined in ) -src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed explanation -error: aborting due to previous error -Could not compile `bindings`. - -To learn more, run the command again with --verbose. -``` - -An error! The compiler won’t let us write a program like this. This is our -first example of the compiler helping us find an error in our program. -Different programming languages have different ways of approaching this -problem. Some languages always initialize values with some sort of default. -Other languages leave the value uninitialized, and make no promises about what -happens if you try to use something before initialization. Rust chooses -something else: error and force the programmer to explain what they want. We -must do some sort of initialization before we can use `x`. - -### Extended error explanations - -There’s one more interesting part of this error message: - -```text -src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed explanation -``` - -We can see an extended explanation by passing the `--explain` flag to `rustc`. -Not every error has a longer explanation, but many of them do. These extended -explanations try to show off common ways that the error occurs, and common -solutions to the issue. Here’s `E0381`: - -```bash -$ rustc --explain E0381 -It is not allowed to use or capture an uninitialized variable. For example: - -fn main() { - let x: i32; - let y = x; // error, use of possibly uninitialized variable - -To fix this, ensure that any declared variables are initialized before being -used. -``` - -These explanations can really help if you’re stuck on an error. The compiler is -your friend, and is here to help. - -## Mutable bindings - -What about changing the value of a binding? Here’s another sample program that -asks this question: - -```rust,ignore -fn main() { - let x = 5; - - x = 6; - - println!("The value of x is: {}", x); -} -``` - -`cargo run` has the answer for us: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:4:5: 4:10 error: re-assignment of immutable variable `x` [E0384] -src/main.rs:4 x = 6; - ^~~~~ -src/main.rs:4:5: 4:10 help: run `rustc --explain E0384` to see a detailed explanation -src/main.rs:2:9: 2:10 note: prior assignment occurs here -src/main.rs:2 let x = 5; - ^ -``` - -The error mentions `re-assigment of immutable variable`. That’s right: bindings -are immutable. But they’re only immutable by default. In a pattern, when we’re -creating a new name, we can add `mut` in front to make the binding a mutable -one. Here’s an example: - -```rust -fn main() { - let mut x = 5; - - println!("The value of x is: {}", x); - - x = 6; - - println!("The value of x is: {}", x); -} -``` - -Running this, we get: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -The value of x is: 6 -``` - -We can now change the value that `x` binds to. Note that the syntax is not `let -mut` exactly; it’s using `mut` in a pattern. This becomes more obvious with our -`()` pattern: - - -```rust,ignore -fn main() { - let (mut x, y) = (5, 6); - - x = 7; - y = 8; -} -``` - -The compiler will complain about this program: - -```bash -$ cargo build - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:5:5: 5:10 error: re-assignment of immutable variable `y` [E0384] -src/main.rs:5 y = 8; - ^~~~~ -src/main.rs:5:5: 5:10 help: run `rustc --explain E0384` to see a detailed explanation -src/main.rs:2:17: 2:18 note: prior assignment occurs here -src/main.rs:2 let (mut x, y) = (5, 6); - ^ -``` - -It’s fine with re-assigning `x`, but not `y`. The `mut` only applies to the -name that follows it, not the whole pattern. - -### Reassignment, not mutation - -There is one subtlety we haven’t covered yet: `mut` allows you to mutate _the -binding_, but not _what the binding binds to_. In other words: - -```rust -fn main() { - let mut x = 5; - - x = 6; -} -``` - -This is not changing the value that `x` is bound to, but creating a new value, -`6`, and changing the binding to bind to it instead. It’s a subtle but -important difference. Well, for now, it does not make a lot of difference, but -when our programs get more complex, it will. Specifically, passing arguments to -functions will illustrate the difference. We’ll talk about that in the next -section, when we discuss functions. - -## Scope - -Variable bindings have a ‘scope’ in which they’re valid. That scope begins from -the point at which the binding is declared, and ends at the end of the next -block of code. We can only access bindings which are ‘in scope’. We cannot -access them ‘before they come into scope’ or ‘after they go out of scope’. -Here’s an example: - -```rust -fn main() { - println!("x is not yet in scope"); - - let x = 5; - println!("x is now in scope"); - - println!("In real code, we’d now do a bunch of work."); - - println!("x will go out of scope now! The next curly brace is ending the main function."); -} -``` - -We can create arbitrary scopes through the use of `{` and `}`: - -```rust -fn main() { - println!("x is not yet in scope"); - - let x = 5; - println!("x is now in scope"); - - println!("Let’s start a new scope!"); - - { - let y = 5; - println!("y is now in scope"); - println!("x is also still in scope"); - - println!("y will go out of scope now!"); - println!("The next curly brace is ending the scope we started."); - } - - println!("x is still in scope, but y is now out of scope and is not usable"); - - println!("x will go out of scope now! The next curly brace is ending the main function."); -} -``` - -What bindings are in and out of scope will become much more important later, -once we learn about ‘references’ and ‘traits’. - -## Shadowing - -A final thing about bindings: they can ‘shadow’ previous bindings with the same -name. Here’s a sample program: - -```rust -fn main() { - let x = 5; - let x = 6; - - println!("The value of x is: {}", x); -} -``` - -Running it, we can see the shadowing in action: - -```text -src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default -src/main.rs:2 let x = 5; - ^ - Running `target/debug/bindings` -The value of x is: 6 -``` - -There are two interesting things in this output. First, Rust will compile and -run this program, no problem. And as we can see, the value of `x` is `6`. But -we didn’t declare `x` as mutable. Instead, we declared a _new_ binding that is -_also_ named `x`, and gave it a new value. The older value that we bound `x` to -is inaccessible as soon as the new `x` is declared. This can be useful if you’d -like to perform a few transformations on a value, and leave it immutable. For -example: - -```rust -fn main() { - let x = 5; - let x = x + 1; - let x = x * 2; - - println!("The value of x is: {}", x); -} -``` - -This will print: - -```bash - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 12 -``` - -This lets us modify `x`, but not deal with mutation. This is nice because we -know that the compiler will let us know if we try to modify it later. Let’s -assume that after we calculate `12`, we don’t want to modify `x` again. If we -had written this program in a mutable style, like this: - -```rust -fn main() { - let mut x = 5; - x = x + 1; - x = x * 2; - - println!("The value of x is: {}", x); - - x = 15; - - println!("The value of x is: {}", x); -} -``` - -Rust is happy to let us mutate it again, to `15`. A similar program in our -immutable style will let us know about that accidental mutation, however: - -```rust,ignore -fn main() { - let x = 5; - let x = x + 1; - let x = x * 2; - - println!("The value of x is: {}", x); - - x = 15; - - println!("The value of x is: {}", x); -} -``` - -If we try to compile, we get an error: - -```bash -$ cargo build - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:8:5: 8:11 error: re-assignment of immutable variable `x` [E0384] -src/main.rs:8 x = 15; - ^~~~~~ -src/main.rs:8:5: 8:11 help: run `rustc --explain E0384` to see a detailed explanation -src/main.rs:4:9: 4:10 note: prior assignment occurs here -src/main.rs:4 let x = x * 2; - ^ -error: aborting due to previous error -Could not compile `bindings`. -``` - -Exactly what we wanted. - -Shadowing can take some time to get used to, but it’s very powerful, and works -well with immutability. - -There was one more thing we should talk about in the output from compiling our -initial program. It’s this part: - -```text -src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default -``` - -Here’s the two lines of relevant code: - -```rust -let x = 5; -let x = 6; -``` - -Rust knows that we shadowed `x`, but we never ended up using the initial value. -This isn’t _wrong_, exactly, it just may not have been what we wanted. In this -case, the compiler issues a ‘warning’, but still compiles our program. The -`#[warn(unused_variables)]` syntax is called an ‘attribute’, which we’ll -discuss in a later section. More specifically, a warning like this is called a -‘lint’, which is an old term for the bits of sheep’s wool that you wouldn’t -want to put in cloth. Similarly, this lint is telling us that we may have an -extra bit of code we don’t need. Our program would work just fine without it. -It’s worth listening to these warnings, and fixing the problems they point out. -They can be signs of a larger problem. In this case, we may not have realized -that we were shadowing `x`. - -### Shadowing and scopes - -Like any binding, a binding that shadows another binding will go away at the -end of a scope. Here’s an example program: - -```rust -fn main() { - let x = 5; - - println!("Before shadowing, x is: {}", x); - - { - let x = 6; - - println!("Now that x is shadowed, x is: {}", x); - } - - println!("After shadowing, x is: {}", x); -} -``` - -If we run this example, we can see the shadow appear and disappear: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -Before shadowing, x is: 5 -Now that x is shadowed, x is: 6 -After shadowing, x is: 5 -``` diff --git a/src/ch03-03-variable-bindings-in-detail.md b/src/ch03-03-variable-bindings-in-detail.md new file mode 100644 index 0000000000..efb6461024 --- /dev/null +++ b/src/ch03-03-variable-bindings-in-detail.md @@ -0,0 +1,572 @@ +## Variable Bindings in Detail + +So far, we’ve created the simplest kind of variable binding, but the `let` +statement has some more tricks up its sleeve. Now we'll look at doing more +complex things: creating multiple bindings at once, adding type annotations, +creating mutating bindings, understanding shadowing, and more. + +### Creating Multiple Bindings + +The previous example program just bound one variable, but it's also possible to +create multiple variable bindings in one go. Let’s try a more complex example, +creating two variable bindings at once. Change your example program to this: + + + +```rust +fn main() { + let (x, y) = (5, 6); + + println!("The value of x is: {}", x); + println!("The value of y is: {}", y); +} +``` + +And enter `cargo run` to run it: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) + Running `target/debug/bindings` +The value of x is: 5 +The value of y is: 6 +``` + +We’ve created two bindings with one `let` statement! The `let` statement binds +the values in `(5, 6)` to the corresponding patterns of `(x, y)`. The first +value `5` binds to the first part of the pattern, `x`, and the second value `6` +binds to `y`. We could alternatively have used two `let` statements to the same +effect, as follows: + +```rust +fn main() { + let x = 5; + let y = 6; +} +``` + +In simple cases like this, where we are only binding two variables, two `let` +statements may be clearer in the code, but when you're creating many multiple +bindings, it's useful to be able to do so all at once. Deciding which technique +to use is mostly a judgement call, and as you become more proficient in Rust, +you’ll be able to figure out which style is better in each case. + +### Delayed Initialization + +The examples so far have all provided bindings with an initial value, but that +isn't always necessary. Rather, we can assign a value for the binding later, +after the `let` statement. To try this out, write the following program: + +```rust +fn main() { + let x; + + x = 5; + + println!("The value of x is: {}", x); +} +``` + +And enter `cargo run` to run it: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) + Running `target/debug/bindings` +The value of x is: 5 +``` + +As you can see, this works just like the previous program, in which we assigned +an initial value. + +This raises an interesting question: what happens if we try to print out a +binding before we declare a value? Let's find out. Modify your code to look +like the following: + +```rust,ignore +fn main() { + let x; + + println!("The value of x is: {}", x); + + x = 5; +} +``` + +When you enter `cargo run` to run this code, you should see output like this +after the command: + +```bash + Compiling bindings v0.1.0 (file:///projects/bindings) +src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x` [E0381] +src/main.rs:4 println!("The value of x is: {}", x); + ^ +:2:25: 2:56 note: in this expansion of format_args! +:3:1: 3:54 note: in this expansion of print! (defined in ) +src/main.rs:4:5: 4:42 note: in this expansion of println! (defined in ) +src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed explanation +error: aborting due to previous error +Could not compile `bindings`. + +To learn more, run the command again with --verbose. +``` + +There's been an error! The compiler won’t let us write a program like this, and +instead it requests that you assign a value to the variable `x`. This is our +first example of the compiler helping us find an error in our program. +Different programming languages have different ways of approaching this +problem. Some languages will always initialize values with some sort of +default. Other languages leave the value uninitialized, and make no promises +about what happens if you try to use something before initialization. Rust +responds with an error to prod the programmer to declare the value they want. +We must initialize any variable before we can use it. + +PROD: START BOX +######Extended Error Explanations + +Now that you've seen an example of a Rust error, I want to point out one +particularly useful aspect of errors. Rust encourages you to seek further +information on the kind of error you've received with output like this: + +```bash +src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed explanation +``` + +This tells us that if we pass the `--explain` flag to `rustc` with the provided +error code, we can see an extended explanation, which will try to explain +common causes of and solutions to that kind of error. Not every error has a +longer explanation, but many do. Here’s the explanation for the `E0381` error +we received previously: + +```bash +$ rustc --explain E0381 +It is not allowed to use or capture an uninitialized variable. For example: + +fn main() { + let x: i32; + + let y = x; // error, use of possibly uninitialized variable + +To fix this, ensure that any declared variables are initialized before being +used. +``` + +These explanations can really help if you’re stuck on an error, so don't +hesitate to look up the error code. The compiler is your friend, and it's there +to help. + +PROD: END BOX + +### Mutable bindings + +By default, variable bindings are *immutable*, meaning that once a value is +bound, you can't change that value. Try writing the following sample program to +illustrate this: + +```rust,ignore +fn main() { + let x = 5; + + x = 6; + + println!("The value of x is: {}", x); +} +``` + +Save and run the program, and you should receive another error message, as in +this output: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) +src/main.rs:4:5: 4:10 error: re-assignment of immutable variable `x` [E0384] +src/main.rs:4 x = 6; + ^~~~~ +src/main.rs:4:5: 4:10 help: run `rustc --explain E0384` to see a detailed explanation +src/main.rs:2:9: 2:10 note: prior assignment occurs here +src/main.rs:2 let x = 5; + ^ +``` + +The error includes the message `re-assigment of immutable variable` because the +program tried to assign a second value to the `x` variable. But bindings are +immutable only by default; you can make them mutable by adding `mut` in front +of the variable name. For example, change the program you just wrote to the +following: + +```rust +fn main() { + let mut x = 5; + + println!("The value of x is: {}", x); + + x = 6; + + println!("The value of x is: {}", x); +} +``` + +Running this, we get: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) + Running `target/debug/bindings` +The value of x is: 5 +The value of x is: 6 +``` + +Using `mut`, we change the value that `x` binds to from `5` to `6`. Note, +however, that `mut` is part of the pattern in the `let` statement. This becomes +more obvious if we try to add mutability to a pattern that binds multiple +variables in the same way as we did for a single variable, like this: + + +```rust,ignore +fn main() { + let (mut x, y) = (5, 6); + + x = 7; + y = 8; +} +``` + +If you run this code, the compiler will output an error: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) +src/main.rs:5:5: 5:10 error: re-assignment of immutable variable `y` [E0384] +src/main.rs:5 y = 8; + ^~~~~ +src/main.rs:5:5: 5:10 help: run `rustc --explain E0384` to see a detailed explanation +src/main.rs:2:17: 2:18 note: prior assignment occurs here +src/main.rs:2 let (mut x, y) = (5, 6); + ^ +``` + +The way `mut` is used here, the compiler is fine with reassigning the `x` +variable, but not the `y` variable. That's because `mut` only applies to the +name that directly follows it, not the whole pattern. For the compiler to allow +you to reassign the `y` variable, you'd need to write the pattern as `(mut x, +mut y)` instead. + + + +One thing to know about mutating bindings: `mut` allows you to mutate _the +binding_, but not _what the name binds to_. In other words, the value is not +what changes, but rather the path between the value and the name. For example: + +```rust +fn main() { + let mut x = 5; + + x = 6; +} +``` + +This does not change the value that `x` is bound to, but creates a new value +(`6`) and changes the binding so that it binds the name `x` to this new value +instead. This subtle but important difference will become more important as +your Rust programs get more complex. + + + +### Variable Binding Scope + +Another important thing to know about variable bindings is that they are only +valid as long as they are *in scope*. That scope begins at the point where the +binding is declared, and ends with the curly brace that closes the block of +code containing that binding. We cannot access bindings "before they come into +scope" or "after they go out of scope." Here’s an example to illustrate this: + + + +```rust +fn main() { + println!("x is not yet in scope"); + + let x = 5; + + println!("x is now in scope"); + + println!("In real code, we’d now do a bunch of work."); + + println!("x will go out of scope now! The next curly brace is ending the main function."); +} +``` + +The variable binding for `x` goes out of scope with the last curly brace in the +`main()` function. + +This example only has one scope, though. In Rust, it's possible to create +arbitrary scopes within a scope by placing code within another pair of curly +braces (we'll look at this more in the next chapter). For example: + +```rust +fn main() { + + println!("x is not yet in scope"); + + let x = 5; + + println!("x is now in scope"); + + println!("Let’s start a new scope!"); + + { + let y = 5; + + println!("y is now in scope"); + println!("x is also still in scope"); + + println!("y will go out of scope now!"); + println!("The next curly brace is ending the scope we started."); + } + + println!("x is still in scope, but y is now out of scope and is not usable"); + + println!("x will go out of scope now! The next curly brace is ending the main function."); +} +``` + +The `y` variable is only in scope in the section of the code that's between the +nested pair of curly braces, whereas `x` is in scope from the `let` statement +that binds it until the final curly brace. The scope of bindings will become +much more important later as you learn about references in Chapter XX. + +### Shadowing Earlier Bindings + + + +One final thing about bindings: they can *shadow* previous bindings with the +same name. Shadowing is what happens when you declare two bindings with the +same name. We say that the first binding is ‘shadowed’ by the second, which +means that the second binding's value is what you will see when you use the +variable after the second binding. This can be useful if you’d like to perform +a few transformations on a value, but still leave the binding immutable. For +example: + +```rust +fn main() { + let x = 5; + + let x = x + 1; + + let x = x * 2; + + println!("The value of x is: {}", x); +} +``` + +This program first binds `x` to a value of `5`. Then, it shadows `x`, taking +the original value and adding `1` so that the value of `x` is then `6`. The +third `let` statement shadows `x` again, taking the previous value and +multiplying it by `2` to give `x` a final value of `12`. If you run this, it +will output: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) + Running `target/debug/bindings` +The value of x is: 12 +``` + +Shadowing is useful because it lets us modify `x` without having to make the +variable mutable. This means the compiler will still warn us if we accidentally +try to mutate `x` directly later. For example, say after calculating `12` we +don’t want `x` to be modified again; if we write the program in a mutable +style, like this: + +```rust +fn main() { + let mut x = 5; + + x = x + 1; + x = x * 2; + + println!("The value of x is: {}", x); + + x = 15; + + println!("The value of x is: {}", x); +} +``` + +Rust is happy to let us mutate `x` again, to `15`. A similar program using the +default immutable style, however, will let us know about that accidental +mutation. Here's an example: + +```rust,ignore +fn main() { + let x = 5; + let x = x + 1; + let x = x * 2; + + println!("The value of x is: {}", x); + + x = 15; + + println!("The value of x is: {}", x); +} +``` + +If we try to compile this, we get an error: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) +src/main.rs:8:5: 8:11 error: re-assignment of immutable variable `x` [E0384] +src/main.rs:8 x = 15; + ^~~~~~ +src/main.rs:8:5: 8:11 help: run `rustc --explain E0384` to see a detailed explanation +src/main.rs:4:9: 4:10 note: prior assignment occurs here +src/main.rs:4 let x = x * 2; + ^ +error: aborting due to previous error +Could not compile `bindings`. +``` + +Since we don't want the binding to be mutable, this exactly what should happen. + +#### Shadowing Over Bindings + +You can also shadow bindings over one another, without re-using the initial +binding in the value. Here's how that looks: + +```rust +fn main() { + let x = 5; + let x = 6; + + println!("The value of x is: {}", x); +} +``` + +Running this sample program, we can see the shadowing in action: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) +src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default +src/main.rs:2 let x = 5; + ^ + Running `target/debug/bindings` +The value of x is: 6 +``` + +Rust gives the value of `x` as `6`, which is the value from the *second* `let` +statement. There are a few interesting things in this output. First, that Rust +will compile and run the program without issue. This is because we haven't +mutated the value; instead, we declared a _new_ binding that is _also_ named +`x`, and gave it a new value. + +The other interesting thing in this output is this error line: + +```bash +src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default +``` + +Rust is pointing out that we shadowed `x`, but never used the initial value. +Doing so isn’t _wrong_, but Rust is checking whether this is intentional and +not just a mistake. In this case, the compiler issues a warning, but still +compiles our program. A warning like this is called a *lint*, which is an old +term for the bits of fluff and fibers in sheep’s wool that you wouldn't want to +put in cloth. + +Similarly, this lint is telling us that we may have an extra bit of code (the +statement `let x = 5`) that we don’t need. Even though our program works just +fine, listening to these warnings and fixing the problems they point out is +worthwhile, as they can be signs of a larger problem. In this case, we may not +have realized that we were shadowing `x`, when we meant to, say, define a new +variable with a different name. + +Shadowing can take some time to get used to, but it’s very powerful and works +well with immutability. + +#### Shadowing and Scopes + +Like any binding, a binding that shadows another binding becomes invalid at the +end of a scope. Here’s an example program to illustrate this: + +```rust +fn main() { + let x = 5; + + println!("Before shadowing, x is: {}", x); + + { + let x = 6; + + println!("Now that x is shadowed, x is: {}", x); + } + + println!("After shadowing, x is: {}", x); +} +``` + +This code first creates the `x` variable and prints `x` to the terminal. Then, +inside a new scope, it creates a new binding for `x` with a new value, and +prints that value. When the arbitrary scope ends, `x` is printed once more. If +we run this example, we can see the shadow appear and disappear in the output: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) + Running `target/debug/bindings` +Before shadowing, x is: 5 +Now that x is shadowed, x is: 6 +After shadowing, x is: 5 +``` + +In this case, the binding value reverts to the original value once the shadow +binding goes out of scope. From 7ad59a1a9e0e7e1082a7d664e415e2a8848e1f5a Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 3 Jul 2016 14:54:25 -0400 Subject: [PATCH 036/204] Backport changes to scalar/compound data types sections --- src/SUMMARY.md | 3 +- src/ch03-04-data-types-in-rust.md | 510 ++++++++++++++++++++++++++++++ src/ch03-04-scalar-types.md | 116 ------- src/ch03-05-compound-types.md | 234 -------------- 4 files changed, 511 insertions(+), 352 deletions(-) create mode 100644 src/ch03-04-data-types-in-rust.md delete mode 100644 src/ch03-04-scalar-types.md delete mode 100644 src/ch03-05-compound-types.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 53de81193c..20f167609f 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -10,9 +10,8 @@ - [Up and Running](ch03-01-up-and-running.md) - [Anatomy of a Rust Program](ch03-02-anatomy-of-a-rust-program.md) - [Variable Bindings in Detail](ch03-03-variable-bindings-in-detail.md) + - [Data Types in Rust](ch03-04-data-types-in-rust.md) - [Functions](ch03-03-functions.md) - - [Scalar Types](ch03-04-scalar-types.md) - - [Compound Types](ch03-05-compound-types.md) - [Comments](ch03-06-comments.md) - [Control flow with `if`](ch03-07-if.md) - [Loops](ch03-08-loops.md) diff --git a/src/ch03-04-data-types-in-rust.md b/src/ch03-04-data-types-in-rust.md new file mode 100644 index 0000000000..f377793403 --- /dev/null +++ b/src/ch03-04-data-types-in-rust.md @@ -0,0 +1,510 @@ + +## Data Types in Rust + + +Every value in Rust is of a certain *type*, which tells Rust what kind of data +is being given so it knows how to work with that data. You can rely on Rust's ability to +infer types to figure out the type of a binding, or you can annotate it +explicitly if needed. In this section, we'll look at a number of types built +into the language itself split into two subsets of Rust data types: scalar and +compound. First, let's look at how Rust deals with types. + + + + +### Type Inference and Annotation + +Rust is a *statically typed* language, which means that it must know the types +of all bindings at compile time. However, you may have noticed that we didn’t +declare a type for `x` or `y` in our previous examples. + +This is because Rust can often tell the type of a binding without you having to +declare it. Annotating every single binding with a type can take uneccesary +time and make code noisy. To avoid this, Rust uses *type inference*, meaning +that it attempts to infer the types of your bindings by looking at how the +binding is used. Let’s look at the the first `let` statement you wrote again: + +```rust +fn main() { + let x = 5; +} +``` + +When we bind `x` to `5`, the compiler determines that `x` should be a numeric +type based on the value it is bound to. Without any other information, it sets +the `x` variable's type to `i32` (a thirty-two bit integer type) by default. + +If we were to declare the type with the variable binding, that would be called +a *type annotation*. A `let` statement that includes a type annotation would +look like this: + +```text +let PATTERN: TYPE = VALUE; +``` + +The `let` statement now has a colon after the `PATTERN`, followed by the `TYPE` +name. Note that the colon and the `TYPE` go _after_ the `PATTERN`, not inside +the pattern itself. Given this structure, here's how you'd rewrite `let x = 5` +to use type annotation: + +```rust +fn main() { + let x: i32 = 5; +} +``` + +This does the same thing as `let x = 5` but explicitly states that `x` should +be of the `i32` type. This is a simple case, but more complex patterns with +multiple bindings can use type annotation, too. A binding with two variables +would look like this: + +```rust +fn main() { + let (x, y): (i32, i32) = (5, 6); +} +``` + +In the same way as we place the `VALUE` and the `PATTERN` in corresponding +positions, we also match up the position of the `TYPE` with the `PATTERN` it +corresponds to. + + + +There are times when multiple types could be correct, and there is not enough +information in the context for Rust to be able to tell which type you want to +use. In those cases type annotations are required. We will look at some of +those situations later, but for now, let's look at the types available in Rust. + +### Scalar Types + +A *scalar* type is one that represents a single value. There are four key +scalar types in Rust: integers, floating point numbers, booleans, and +characters. You'll likely recognize these from other programming languages, but +let's jump into how they work in Rust. + +#### Integer Types + +An *integer* is a number without a fractional component. We've used one integer +type already in this chapter, the `i32` type. This type declaration indicates +that the value it's associated with should be a signed integer (hence the `i`, +as opposed to a `u` for unsigned) for a 32-bit system. There are a number of +built-in integer types in Rust, shown in Table 3-1. + +| Length | signed | unsigned | +|--------|--------|----------| +| 8-bit | i8 | u8 | +| 16-bit | i16 | u16 | +| 32-bit | i32 | u32 | +| 64-bit | i64 | u64 | +| arch | isize | usize | + +*Table 3-1: Integer types in Rust. The code (for example, i32) is used to +define a type in a function.* + +Each variant can be either signed or unsigned, and has an explicit size. Signed +and unsigned merely refers to whether it is possible for the number to be +either negative or positive, meaning the number needs to have a sign with it +("signed"), or whether it will only ever be positive and can therefore be +represented without a sign ("unsigned"). It's like writing numbers on paper: +when the sign matters, a number is shown with a plus sign or minus sign, but +when it's safe to assume the number is positive, it's shown with no sign. +Signed numbers are stored using two’s complement representation (if you're +unsure what this is you can search for it online; an explanation is outside the +scope of this text). + +Finally, the `isize` and `usize` types depend on the kind of computer your +program is running on: 64-bits if you're on a 64-bit architecture, and 32-bits +if you’re on a 32-bit architecture. + +So how do you know which type of integer to use? If you're unsure, Rust's +defaults are generally good choices, and integer types default to `i32`: it’s +generally the fastest, even on 64-bit systems. The primary situation in which +you'd need to specify `isize` or `usize` is when indexing some sort of +collection, which we'll talk about in the "Arrays" section. + +#### Floating-Point Types + +Rust also has two primitive types for *floating-point numbers*, which are +numbers with decimal points. Rust's floating-point types are `f32` and `f64`, +which are 32 bits and 64 bits in size, respectively. The default type is `f64`, +as it’s roughly the same speed as `f32`, but has a larger precision. Here's an +example showing floating-point numbers in action: + + + + +```rust +fn main() { + let x = 2.0; // f64 + + let y: f32 = 3.0; // f32 +} +``` + +Floating-point numbers are represented according to the IEEE-754 standard. The +`f32` type is a single-precision float, while `f64` has double-precision. + +#### Numeric Operations + +Rust supports the usual basic mathematic operations you’d expect for all of +these number types--addition, subtraction, multiplication, division, and +modulo. This code shows how you'd use each one in a `let` statement: + +```rust +fn main() { + // addition + let sum = 5 + 10; + + // subtraction + let difference = 95.5 - 4.3; + + // multiplication + let product = 4 * 30; + + // division + let quotient = 56.7 / 32.2; + + // modulo + let remainder = 43 % 5; +} +``` + +Each expression in these statements uses a mathematical operator and evaluates +to a single value, which is then bound to a variable. + +#### The Boolean Type + +As in most other programming languages, a boolean type in Rust has two possible +values: `true` and `false`. The boolean type in Rust is specified with `bool`. +For example: + +```rust +fn main() { + let t = true; + + let f: bool = false; // with explict type annotation +} +``` + +The main way to consume boolean values is through conditionals like an `if` +statement. We’ll cover how `if` statements work in Rust in the "Control Flow" +section of this chapter. + +#### The Character Type + +So far we’ve only worked with numbers, but Rust supports letters too. Rust’s +`char` type is the language's most primitive alphabetic type, and this code +shows one way to use it: + +```rust +fn main() { + let c = 'z'; + let z = 'ℤ'; + let heart_eyed_cat = '😻'; +} +``` + +Rust’s `char` represents a Unicode Scalar Value, which means that it can +represent a lot more than just ASCII. Accented letters, Chinese/Japanese/Korean +ideographs, emoji, and zero width spaces are all valid `char`s in Rust. Unicode +Scalar Values range from `U+0000` to `U+D7FF` and `U+E000` to `U+10FFFF` +inclusive. A "character" isn’t really a concept in Unicode, however, so your +human intutition for what a "character" is may not match up with what a `char` +is in Rust. It also means that `char`s are four bytes each. You can learn more +about Unicode Scalar Values at +*http://www.unicode.org/glossary/#unicode_scalar_value* and find a chart for +all unicode code points at *http://www.unicode.org/charts/*. + + + + +### Compound Types + +*Compound types* can group multiple values of other types into one type. Rust +has two primitive compound types: tuples and arrays. You can also put a +compound type inside another compound type. + +#### Grouping Values into Tuples + +We’ve seen tuples already, when binding multiple values at once. A tuple is a +general way of grouping together some number of other values with distinct +types into one compound type. The number of values is called the *arity* of the +tuple. + +We create a tuple by writing a comma-separated list of values inside +parentheses. Each position in the tuple has a distinct type, as in this example: + +```rust +fn main() { + let tup: (i32, f64, u8) = (500, 6.4, 1); +} +``` + +Note that, unlike the examples of multiple bindings, here we bind the single +name `tup` to the entire tuple, emphasizing the fact that a tuple is considered +a single compound element. We can then use pattern matching to destructure this +tuple value, like this: + +```rust +fn main() { + let tup: (i32, f64, u8) = (500, 6.4, 1); + + let (x, y, z) = tup; + + println!("The value of y is: {}", y); +} +``` + +In this program, we first create a tuple, and bind it to the name `tup`. We +then use a pattern with `let` to take `tup` and turn it into three separate +bindings, `x`, `y`, and `z`. This is called ‘destructuring’, because it breaks +the single tuple into three parts. + +Finally, we print the value of `x`, which is `6.4`. + +#### Tuple Indexing + +In addition to destructuring through pattern matching, we can also access a +tuple element directly by using a period (`.`) followed by the index of the +value we want to access. For example: + +```rust +fn main() { + let x: (i32, f64, u8) = (500, 6.4, 1); + + let five_hundred = x.0; + + let six_point_four = x.1; + + let one = x.2; +} +``` + +This program creates a tuple, `x`, and then makes new bindings to each element +by using their index. As with most programming languages, the first index in a +tuple is 0. + +#### Single-Element Tuples + +Not everything contained within parentheses is a tuple in Rust. For example, a +`(5)` may be a tuple, or just a `5` in parentheses. To disambiguate, use a +comma for single-element tuples, as in this example: + +```rust +fn main() { + let x = (5); + + let x = (5,); +} +``` + +In the first `let` statement, because `(5)` has no comma, it's a simple i32 and +not a tuple. In the second `let` example, `(5,)` is a tuple with only one +element. + +### Arrays + +So far, we’ve only represented single values in a binding. Sometimes, though, +it’s useful to bind a name to more than one value. Data structures that contain +multiple values are called *collections*, and arrays are the first type of Rust +collection we’ll learn about. + +In Rust, arrays look like this: + +```rust +fn main() { + let a = [1, 2, 3, 4, 5]; +} +``` + +The values going into an array are written as a comma separated list inside +square brackets. Unlike a tuple, every element of an array must have the same +type. + +#### Type Annotation for Arrays + +When you specify an array’s type, you'd do so as such: + +```rust +fn main() { + let a: [i32; 5] = [1, 2, 3, 4, 5]; +} +``` + +Much like in a variable binding that uses type annotation, the array's type and +length come after the pattern name and a colon. This array has `5` values, +which are of the `i32` type. Unlike the values themselves, the type and array +length are separated by a semicolon. + +#### Using Debug in the println! Macro + +So far, we’ve been printing values using `{}` in a `println!` macro. If we try +that with an array, however, we'll get an error. Say we have the following +program: + +```rust,ignore +fn main() { + let a = [1, 2, 3, 4, 5]; + + println!("a is: {}", a); +} +``` + +This code tries to print the `a` array directly, which may seem innocuous. But +running it produces the following output: + +```bash +$ cargo run + Compiling arrays v0.1.0 (file:///projects/arrays) +src/main.rs:4:25: 4:26 error: the trait `core::fmt::Display` is not implemented for the type `[_; 5]` [E0277] +src/main.rs:4 println!(“a is: {}”, a); + ^ +:2:25: 2:56 note: in this expansion of format_args! +:3:1: 3:54 note: in this expansion of print! (defined in ) +src/main.rs:4:5: 4:28 note: in this expansion of println! (defined in ) +src/main.rs:4:25: 4:26 help: run `rustc --explain E0277` to see a detailed explanation +src/main.rs:4:25: 4:26 note: `[_; 5]` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string +src/main.rs:4:25: 4:26 note: required by `core::fmt::Display::fmt` +error: aborting due to previous error +``` + +Whew! The core of the error is this part: *the trait `core::fmt::Display` is +not implemented*. We haven’t discussed traits yet, so this is bound to be +confusing! Here’s all we need to know for now: `println!` can do many kinds of +formatting. By default, `{}` implements a kind of formatting known as +`Display`: output intended for direct end-user consumption. The primitive types +we’ve seen so far implement `Display`, as there’s only one way you’d show a `1` +to a user. But with arrays, the output is less clear. Do you want commas or +not? What about the `[]`s? + +More complex types in the standard library do not automatically implement +`Display` formatting. Instead, Rust implements another kind of formatting, +intended for the programmer. This formatting type is called `Debug`. To ask +`println!` to use `Debug` formatting, we include `:?` in the print string, like +this: + +```rust +fn main() { + let a = [1, 2, 3, 4, 5]; + + println!("a is {:?}", a); +} +``` + +If you run this, it should print the five values in the `a` array as desired: + +```bash +$ cargo run + Compiling arrays v0.1.0 (file:///projects/arrays) + Running `target/debug/arrays` +a is [1, 2, 3, 4, 5] +``` + +You’ll see this repeated later, with other types. We’ll cover traits fully in +Chapter XX. + +#### Accessing and Modifying Array Elements + +An array is a single chunk of memory, allocated on the stack. We can access +elements of an array using indexing, like this: + +```rust +fn main() { + let a = [1, 2, 3, 4, 5]; + + let first = a[0]; + let second = a[1]; +} +``` + +In this example, the `first` variable will bind to `1` at index `[0]` in the +array, and `second` will bind to `2` at index `[1]` in the array. Note that +these values are copied out of the array and into `first` and `second` when the +`let` statement is called. That means if the array changes after the `let` +statements, these bindings will not, and the two variables should retain their +values. For example, imagine you have the following code: + +```rust +fn main() { + let mut a = [1, 2, 3, 4, 5]; + + let first = a[0]; + + a[0] = 7; + + println!("The value of first is: {}", first); + println!("a is {:?}", a); +} +``` + + + +First, notice the use of `mut` in the array declaration. We had to declare +array `a` as `mut` to override Rust's default immutability. The line `a[0] = +7;` modifies the element at index 0 in the array, changing its value to `7`. +This happens after `first` is bound to the original value at index 0, so +`first` should still be equal to `1`. Running the code will show this is true: + +```text +The value of first is: 1 +a is [7, 2, 3, 4, 5] +``` + +#### Invalid array element access + +What happens if you try to access an element of an array past the end of the +array? Say we changed our program to: + +```rust,ignore +fn main() { + let a = [1, 2, 3, 4, 5]; + + let element = a[10]; + + println!("The value of element is: {}", element); +} +``` + +If we use `cargo run` on a project named `arrays` containing this code: + +```bash +$ cargo run + Compiling arrays v0.1.0 (file:///projects/arrays) + Running `target/debug/arrays` +thread '
' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:4 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +error: Process didn't exit successfully: `target/debug/arrays` (exit code: 101) +``` + +We can see that compiling did not give us any errors, but we got a *runtime* +error and our program didn't exit successfully. When we attempt to access an +element using indexing, Rust will check that the index we've specified is less +than the array length. If the index is greater than the length, it will +"panic", which is what it's called when a Rust program exits with an error. + +This is our first example of Rust’s safety principles in action. In many +low-level languages, this kind of check is not done, and when you provide an +incorrect index, invalid memory can be accessed. Rust protects us against this +kind of error by immediately exiting instead of allowing the memory access and +continuing. We'll discuss more of Rust’s error handling in Chapter xx. diff --git a/src/ch03-04-scalar-types.md b/src/ch03-04-scalar-types.md deleted file mode 100644 index ce2209aab0..0000000000 --- a/src/ch03-04-scalar-types.md +++ /dev/null @@ -1,116 +0,0 @@ -# Scalar Types - -We’ve seen that every value in Rust has a type of some kind. There are a number -of types which are built into the language itself. First, we’ll take a look at -‘scalar’ types, that is, types which represent a single value. - -Remember, you can rely on type inference to figure out the type of a binding, -or you can annotate it explicitly: - -```rust -fn main() { - let x: i32 = 5; -} -``` - -## Integers - -You’ve already seen one primitive type: `i32`. There are a number of built-in -number types in Rust. - -Here’s a chart of Rust’s integer types: - -| | signed | unsigned | -|--------|--------|----------| -| 8-bit | i8 | u8 | -| 16-bit | i16 | u16 | -| 32-bit | i32 | u32 | -| 64-bit | i64 | u64 | -| arch | isize | usize | - -We have both signed and unsigned variants of numbers, and each variant has an -explicit size. Unsigned numbers are never negative, and signed numbers can be -positive or negative. (Think ‘plus sign’ or ‘minus sign’: that’s a signed -number.) Signed numbers are stored using ‘two’s complement’ representation. - -Finally, `isize` and `usize` are different sizes based on the kind of computer -your program is running on. If you are on a 64-bit architecture, they are 64 -bits, and if you’re on a 32-bit one, they’re 32 bits. - -So how do you choose from all these options? Well, if you really don’t know, -the defaults are a good choice: integer types default to `i32`. The primary use -case for `isize`/`usize` is when indexing some sort of collection. We’ll talk -more about our first collection, arrays, in just a moment. - -## Floating-point numbers - -Rust also has two primitive floating-point numbers: `f32` and `f64`. They are -32 bits and 64 bits in size, respectively. The default is `f64`. - -```rust -fn main() { - let x = 2.0; // f64 - - let y: f32 = 3.0; // f32 -} -``` - -Floating-point numbers are represented according to the IEEE-754 standard. -`f32` is a single-precision float, `f64` is double-precision. - -## Numeric operations - -Rust supports the usual operations you’d expect on all of these number types: - -```rust -fn main() { - // addition - let sum = 5 + 10; - - // subtraction - let difference = 95.5 - 4.3; - - // multiplication - let product = 4 * 30; - - // division - let quotient = 56.7 / 32.2; - - // modulus - let remainder = 43 % 5; -} -``` - -## Booleans - -Somewhat fundamental to all computing, Rust has a boolean type, `bool`, with -two possible values: - -```rust -fn main() { - let t = true; - let f: bool = false; // with explict type annotation -} -``` - -The main way to consume boolean values is through conditionals like `if`, which -we’ll see later in the chapter. - -## Characters - -We’ve only worked with numbers so far, but what about letters? Rust’s most -primitive alphabetic type is the `char`: - -```rust -fn main() { - let c = 'z'; - let z = 'ℤ'; -} -``` - -Rust’s `char` represents a [Unicode Scalar Value], which means that it can -represent a lot more than just ASCII. ‘Character’ isn’t really a concept in -Unicode, however: your human intutition for what a ‘character’ is may not match -up with a `char`. It also means that `char`s are four bytes each. - -[Unicode Scalar Value]: http://www.unicode.org/glossary/#unicode_scalar_value diff --git a/src/ch03-05-compound-types.md b/src/ch03-05-compound-types.md deleted file mode 100644 index c648ff5ea0..0000000000 --- a/src/ch03-05-compound-types.md +++ /dev/null @@ -1,234 +0,0 @@ -# Compound Types - -Now that we’ve discussed scalar types, let’s talk about compound types. -These types can group multiple values of scalar types into another type. - -## Tuples - -We’ve seen tuples before, in the guise of binding or returning multiple values -at once. It turns out that there’s no magic here: tuples are a general way of -making a compound value that groups some number of other values with distinct -types. The number of values grouped is the ‘arity’ of the tuple. - -We create a tuple by writing a comma-separated list of values inside -parentheses; each position in the tuple has a distinct type: - -```rust -fn main() { - let tup: (i32, f64, u8) = (500, 6.4, 1); -} -``` - -Note that, unlike the examples of multiple bindings, here we bound the -single name `tup` to the entire tuple. We can then use pattern -matching to destructure this tuple value: - -```rust -fn main() { - let tup: (i32, f64, u8) = (500, 6.4, 1); - let (x, y, z) = tup; - - println!("The value of y is: {}", y); -} -``` - -Tuples are used sparingly in Rust code. This is because the elements of a tuple -are anonymous, which can make code hard to read. - -### Tuple indexing - -In addition to destructuring through pattern matching, we can also access a -tuple element directly using `.`, followed by the index we want to access: - -```rust -fn main() { - let x: (i32, f64, u8) = (500, 6.4, 1); - - let five_hundred = x.0; - let six_point_four = x.1; - let one = x.2; -} -``` - -As you can see, the first index is `0`. - -### Single-element tuples - -There’s one last trick with tuples: `(5)` is actually ambiguous: is it a tuple, -or is it a `5` in parethesis? If you need to disambiguate, use a comma: - -```rust -fn main() { - let x = (5); // x is an i32, no tuple. Think of it like (5 + 1) without the + 1, they’re for grouping. - - let x = (5,); // x is a (i32), a tuple with one element. -} -``` - -## Arrays - -So far, we’ve only represented single values in a binding. Sometimes, though, -it’s useful to have more than one value. These kinds of data structures are -called ‘collections’, and arrays are the ones we’ll learn about first. Arrays -look like this: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; -} -``` - -An array’s type consists of the type of the elements it contains, as well as -the length: - -```rust -fn main() { - let a: [i32; 5] = [1, 2, 3, 4, 5]; -} -``` - -An array is a single chunk of memory, allocated on the stack. - -We can access elements of an array using indexing: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; - - let first = a[0]; - let second = a[1]; -} -``` - -In this example, `first` will hold the value `1`, and `second` will be bound to -`2`. Note that these values are copied out of the array; if the array changes, -these bindings will not. Here’s an example, which also shows us how we can -modify elements of the array: - -```rust -fn main() { - let mut a = [1, 2, 3, 4, 5]; - - let first = a[0]; - - a[0] = 7; - - println!("The value of first is: {}", first); -} -``` - -Running this example will show that `first` is still `1`. If we didn’t want a -copy, but instead wanted to refer to the first element, whatever its value was, -we need a new concept. We’ll talk about ‘references’ in Section 4. - -One last thing: now that we are modifying the array, `a` needs to be declared -`mut`. - -Arrays are our first real data structure, and so there’s a few other concepts -that we haven’t covered in full yet. There are two: the `panic!` macro, and a -new way of printing things: `Debug`. - -### Panic - -We showed what happens when you access elements of an array, but what if we -give an invalid index? - -```rust,should_panic -fn main() { - let a = [1, 2, 3, 4, 5]; - - let invalid = a[10]; - - println!("The value of invalid is: {}", invalid); -} -``` - -If we run this example, we will get an error. Let’s re-use our `functions` -project from before. Change your `src/main.rs` to look like the example, and -run it: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -thread ‘
’ panicked at ‘index out of bounds: the len is 5 but the index is 10’, src/main.rs:4 -Process didn’t exit successfully: `target/debug/functions` (exit code: 101) -``` - -It says that our thread panicked, and that our program didn’t exit -successfully. There’s also a reason: we had a length of five, but an index of -10. - -For now, all you need to know is that a panic will crash your program. Rust’s -error handling story is described in full in a later chapter. - -So why did this code panic? Well, arrays know how many elements they hold. When -we access an element via indexing, Rust will check that the index is less than -the length. If it’s greater, it will panic, as something is very wrong. This is -our first example of Rust’s safety principles in action. In many low-level -languages, this kind of check is not done. If you have an incorrect index, -invalid memory can be accessed. Rust protects us against this kind of error. - -### Debug - -So far, we’ve been printing values using `{}`. If we try that with an array, -though... - -```rust,ignore -fn main() { - let a = [1, 2, 3, 4, 5]; - - println!("a is: {}", a); -} -``` - -... we will get an error: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) -src/main.rs:4:25: 4:26 error: the trait `core::fmt::Display` is not implemented for the type `[_; 5]` [E0277] -src/main.rs:4 println!(“a is {}”, a); - ^ -:2:25: 2:56 note: in this expansion of format_args! -:3:1: 3:54 note: in this expansion of print! (defined in ) -src/main.rs:4:5: 4:28 note: in this expansion of println! (defined in ) -src/main.rs:4:25: 4:26 help: run `rustc --explain E0277` to see a detailed explanation -src/main.rs:4:25: 4:26 note: `[_; 5]` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string -src/main.rs:4:25: 4:26 note: required by `core::fmt::Display::fmt` -error: aborting due to previous error -``` - -Whew! The core of the error is this part: the trait `core::fmt::Display` is not -implemented. We haven’t discussed traits yet, so this is bound to be confusing! -Here’s all we need to know for now: `println!` can do many kinds of formatting. -By default, `{}` implements a kind of formatting known as `Display`: output -intended for direct end-user consumption. The primitive types we’ve seen so far -implement `Display`, as there’s only one way you’d show a `1` to a user. But -with arrays, the output is less clear. Do you want commas or not? What about -the `[]`s? - -Due to these questions, more complex types in the standard library do not -implement `Display` formatting. There is another kind of formatting, `Debug`, -which is a bit different: intended for programmer consumption. We can ask -`println!` to use `Debug` formatting with `:?`: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; - - println!("a is {:?}", a); -} -``` - -This will work: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -a is [1, 2, 3, 4, 5] -``` - -You’ll see this repeated later, with other types. And we’ll cover traits fully -later in the book, Section 9. From 3b6c3090a6ad620f084475571de989d596c36e55 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 3 Jul 2016 14:57:11 -0400 Subject: [PATCH 037/204] Backport changes to functions section --- src/SUMMARY.md | 2 +- src/ch03-03-functions.md | 504 ----------------- src/ch03-05-how-functions-work-in-rust.md | 635 ++++++++++++++++++++++ 3 files changed, 636 insertions(+), 505 deletions(-) delete mode 100644 src/ch03-03-functions.md create mode 100644 src/ch03-05-how-functions-work-in-rust.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 20f167609f..7221a432c0 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -11,7 +11,7 @@ - [Anatomy of a Rust Program](ch03-02-anatomy-of-a-rust-program.md) - [Variable Bindings in Detail](ch03-03-variable-bindings-in-detail.md) - [Data Types in Rust](ch03-04-data-types-in-rust.md) - - [Functions](ch03-03-functions.md) + - [How Functions Work in Rust](ch03-05-how-functions-work-in-rust.md) - [Comments](ch03-06-comments.md) - [Control flow with `if`](ch03-07-if.md) - [Loops](ch03-08-loops.md) diff --git a/src/ch03-03-functions.md b/src/ch03-03-functions.md deleted file mode 100644 index 0b279896ae..0000000000 --- a/src/ch03-03-functions.md +++ /dev/null @@ -1,504 +0,0 @@ -# Functions - -Functions are pervasive in Rust code. We’ve already seen the most important -function, `main()`, in previous sections of the book: - -```rust -fn main() { - println!("Hello, world!"); -} -``` - -We can declare new functions with the `fn` keyword: - -```rust -fn another_function() { - println!("Another function."); -} -``` - -Rust code uses `snake_case` as a style for function names: all lower case, with -underscores separating words. (It also uses them for variable names, too.) We -can can call any function we’ve defined by using its name and some parentheses: - -```rust -fn main() { - println!("Hello, world!"); - - another_function(); -} - -fn another_function() { - println!("Another function."); -} -``` - -Let’s start a new project to explore functions. Open a terminal, and navigate -to the directory where you’d like to keep your projects. From there, use Cargo -to generate a new project: - -```bash -$ cargo new --bin functions -$ cd functions -``` - -Place the new example in `src/main.rs`, and run it: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -Hello, world! -Another function. -``` - -As we can see, the lines execute in order: first, we print out our “Hello, -world!” message, and then `another_function()` is called. It then prints its -message as well. - -## Function Arguments - -Functions can also take arguments: - -```rust -fn main() { - another_function(5); -} - -fn another_function(x: i32) { - println!("The value of x is: {}", x); -} -``` - -Let’s try running it: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of x is: 5 -``` - -Let’s take a closer look at `another_function()`’s signature: - -```rust,ignore -fn another_function(x: i32) { -``` - -Declaring a function which takes a single argument looks like this: - -```text -fn NAME(PATTERN: TYPE) { -``` - -That’s right, patterns appear again. Consider how the parameter declaration -here looks like the `let` bindings we used earlier: - -```rust,ignore -let x: i32; -fn another_function(x: i32) { -``` - -There’s only one difference here: in function signatures, we _must_ declare the -type. This is a deliberate decision; we find that requiring type annotations in -functions means that you almost never need them anywhere else. - -You can separate multiple arguments with a comma: - -```text -fn NAME(PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE...) { -``` - -Here’s a full example: - -```rust -fn main() { - another_function(5, 6); -} - -fn another_function(x: i32, y: i32) { - println!("The value of x is: {}", x); - println!("The value of y is: {}", y); -} -``` - -Let’s try it: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of x is: 5 -The value of y is: 6 -``` - -We could also create bindings, and pass them in as arguments: - -```rust -fn main() { - let a = 5; - let b = 6; - - another_function(a, b); -} - -fn another_function(x: i32, y: i32) { - println!("The value of x is: {}", x); - println!("The value of y is: {}", y); -} -``` - -This has the same effect: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of x is: 5 -The value of y is: 6 -``` - -Note that our bindings are called `a` and `b`, yet inside of the function, we -refer to them by the names in the signature, `x` and `y`. Inside a function, -only its parameters are in scope, so we need to use those names. Bindings -passed as parameters don’t need to have the same name as the arguments. - -## Return values - -Functions can also return values back to the function that called them: - -```TEXT -fn NAME(PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE...) -> TYPE { -``` - -We don’t name return values, but we do declare their type, after an arrow: -`->`. Here’s a sample program: - -```rust -fn main() { - let x = five(); - - println!("The value of x is: {}", x); -} - -fn five() -> i32 { - 5 -} -``` - -Let’s try running it: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of x is: 5 -``` - -Let’s examine this in more detail. There are two important bits. First, we can -use the return value of a function to initialize a binding: - -```rust,ignore -let x = five(); -``` - -Because `five()` returns a `5`, this is the same as: - -```rust -let x = 5; -``` - -The second interesting bit is `five()` itself: - -```rust -fn five() -> i32 { - 5 -} -``` - -We have no arguments, and our return type, `i32`. However, the body of this -function is a lonely `5`. There’s a detail here that you may or may not have -noticed: we’ve ended almost every line in our programs with a semicolon. -There’s no semicolon here, though. Why not? - -The answer to this question is: - -> The return value of a function is the value of its final expression. - -We haven’t talked about expressions yet, so this definition doesn’t help a lot. -Let’s go over that now. - -## Statements and Expressions - -Expressions are bits of code that evaluate to a value. Consider some math -operations, like this: - -```rust,ignore -5 + 6 -``` - -We can evaluate this expression, and come up with a value: `11`. In Rust, most -bits of code are expressions. For example, calling a function is an expression: - -```rust,ignore -foo(5) -``` - -The value is equal to whatever the return value of `foo()` is. - -So why does this matter? Well, not everything is an expression. Some things are -‘statements’. Expressions _compute_ something, but statements _bind_ or _do_ -something. It’s a subtle difference. We’ve already seen two kinds of -statements: `let` statements, and `fn` declarations. - -Because `let` is a statement, not an expression, you can’t assign it to another -binding. Here’s an example that doesn’t work: - -```rust,ignore -fn main() { - let x = (let y = 6); -} -``` - -If we try to run this program, we’ll get an error: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) -src/main.rs:2:14: 2:17 error: expected identifier, found keyword `let` -src/main.rs:2 let x = (let y = 6); - ^~~ -src/main.rs:2:18: 2:19 error: expected one of `!`, `)`, `,`, `.`, `::`, `{`, or an operator, found `y` -src/main.rs:2 let x = (let y = 6); - ^ -Could not compile `functions`. -``` - -We also cannot somehow assign a `fn` declaration to a binding, either. - -So what’s this have to do with return values? Well, `{}`, a ‘block’ that we -used earlier to create new scopes, _is_ an expression. Let’s take a closer look -at `{}`. It looks like this: - -```text -{ - STATEMENT* - EXPRESSION -} -``` - -The `*` there means ‘zero or more’, so we can have any number of statements -followed by an expression. Since blocks are expressions themselves, we can nest -blocks inside of blocks. And since they return a value, we can use them in -`let` statements: - -```rust -fn main() { - let x = 5; - - let y = { - let z = 1; - - x + z + 5 - }; - - println!("The value of y is: {}", y); -} -``` - -Let’s try running this program: - -```bash - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of y is: 11 -``` - -We’re now using a block to give us a value for `y`: - -```rust,ignore -let y = { - -}; -``` - -Since the block can contain statements, we create a new variable binding, `z`, -and give it a value. We then do some math for the final expression of the -block: - -```rust,ignore -{ - let z = 1; - - x + z + 5 -} -``` - -`5 + 1 + 5` is `11`, and so the value of the entire block is `11`. This gets -substituted into our `let` statement for `y`: - -```rust,ignore -let y = 11; -``` - -Hence our output saying `y` is `11`. - -Where else do we use blocks? As the body of functions! They’re very similar: - -```rust -fn main() { - let x = 5; - - let y = { - x + 1 - }; - - println!("The value of y is: {}", y); - - let y = plus_one(x); - - println!("The value of y is: {}", y); -} - -fn plus_one(x: i32) -> i32 { - x + 1 -} -``` - -Running this gives: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of y is: 6 -The value of y is: 6 -``` - -In both cases, we use a block to produce a value. In the first case, it’s -assigning with `let`: - -```rust,ignore -let y = { -``` - -In the second, it’s the return value of the function: - -```rust,ignore -fn plus_one(x: i32) -> i32 { -``` - -### Expression statements - -There’s one more detail about expressions and statements: a semicolon takes any -expression, and turns it into a statement. Let’s accidentally cause an error -with `plus_one()`: - -```rust,ignore -fn main() { - let x = plus_one(5); - - println!("The value of x is: {}", x); -} - -fn plus_one(x: i32) -> i32 { - x + 1; -} -``` - -Instead of an expression, `x + 1`, we’ve now turned it into a statement, -`x + 1;`. - -Running this gives an error: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) -src/main.rs:7:1: 9:2 error: not all control paths return a value [E0269] -src/main.rs:7 fn plus_one(x: i32) -> i32 { -src/main.rs:8 x + 1; -src/main.rs:9 } -src/main.rs:7:1: 9:2 help: run `rustc --explain E0269` to see a detailed explanation -src/main.rs:8:10: 8:11 help: consider removing this semicolon: -src/main.rs:8 x + 1; - ^ -error: aborting due to previous error -Could not compile `functions`. -``` - -Rust has our back here: it even suggests removing the semicolon, which fixes -the error. But the main error message is the core of the issue: statements -don’t evaluate to a value, yet we want to return an `i32`. - -In practice, Rust programmers don’t often think about these rules at this -level. Usually, you have a semicolon at the end of most lines, and maybe not at -the end of blocks. - -## Multiple return values - -Functions cannot directly return multiple values. There’s a trick, however. -Remember the `()`s we used when showing off complex bindings? - -```rust -fn main() { - let (x, y) = (5, 6); -} -``` - -They form something called a ‘tuple’, one of Rust’s basic types. A tuple is an -anonymous collection of elements. But since a tuple is a singular thing, we can -use it as a way to return multiple values from functions: - -```rust -fn main() { - let (x, y) = two_numbers(); - - println!("The value of x is: {}", x); - println!("The value of y is: {}", y); -} - -fn two_numbers() -> (i32, i32) { - (5, 6) -} -``` - -Running this will show us the values: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of x is: 5 -The value of y is: 6 -``` - -There are two interesting changes here: assigning the return value of -`two_numbers()` to `x` and `y`, and the declaration of `two_numbers()` itself. - -Let’s look at the declaration first: - -```rust -fn two_numbers() -> (i32, i32) { - (5, 6) -} -``` - -The `(i32, i32)` should look familiar. We saw it in `let` bindings earlier: - -```rust -let (x, y): (i32, i32) = (5, 6); -``` - -The `(i32, i32)` syntax says “a tuple with two `i32`s in it.” The `(5, 6)` -syntax creates a new one, with `5` and `6`. - -This tuple is then returned, and assigned to `x` and `y`: - -```rust,ignore -let (x, y) = two_numbers(); -``` - -See how all these bits fit together? - -We call this behavior of `let` ‘destructuring’, because it takes the structure -of the expression that comes after the `=` and takes it apart. diff --git a/src/ch03-05-how-functions-work-in-rust.md b/src/ch03-05-how-functions-work-in-rust.md new file mode 100644 index 0000000000..e3f786b158 --- /dev/null +++ b/src/ch03-05-how-functions-work-in-rust.md @@ -0,0 +1,635 @@ +## How Functions Work in Rust + +Functions are pervasive in Rust code. We’ve already seen one of the most +important functions in the language: the `main()` function that’s the entry +point of every program. We've also seen the `fn` keyword, which allows us to +declare new functions. + +Rust code uses *snake case* as the conventional style for function names. In +snake case, all letters are lower case, and there are underscores separating +words. (Rust also uses snake case for the names of variable bindings; we just +haven't used any variable bindings long enough to need underscores yet.) Here's +a program containing an example function definition: + +```rust +fn main() { + println!("Hello, world!"); + + another_function(); +} + +fn another_function() { + println!("Another function."); +} +``` + +Function definitions in Rust always start with `fn` and have a set of parentheses after the function name. The curly +braces tell the compiler where the function body begins and ends. + +We can call any function we’ve defined by entering its name followed by a pair +of parentheses. Since `another_function()` is defined in the program, it can be +called from inside the `main()` function. Note that we defined +`another_function()` _after_ the `main()` function in our source code; we could +have defined it before as well. Rust doesn’t care where you define your +functions, only that they are defined somewhere. + +Let’s start a new project to explore functions further. Open a terminal, and +navigate to the directory you're keeping your projects in. From there, use +Cargo to generate a new project, as follows: + +```bash +$ cargo new --bin functions +$ cd functions +``` + +Place the `another_function()` example in a file named *src/main.rs* and run +it. You should see the following output: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +Hello, world! +Another function. +``` + +The lines execute in the order they appear in the `main()` function. First, our +“Hello, world!” message prints, and then `another_function()` is called and its +message is printed. + +### Function Arguments + +Functions can also take arguments. The following rewritten version of +`another_function()` shows what arguments look like in Rust: + +```rust +fn main() { + another_function(5); +} + +fn another_function(x: i32) { + println!("The value of x is: {}", x); +} +``` + +Try running this program, and you should get this output: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +The value of x is: 5 +``` + +Since we passed `5` to `another_function()`, the `println!` macro put `5` where +the pair of curly braces were in the format string. + +Let’s take a closer look at the signature of a function which takes a single +argument: + +```text +fn NAME(PATTERN: TYPE) { +``` + +The parameter declaration in a single-argument function signature looks like +the `let` bindings we used earlier. Just look at both together, and compare +them: + + + +```rust,ignore +let x: i32; +fn another_function(x: i32) { +``` + +The one difference is that in function signatures, we _must_ declare the type. +This is a deliberate decision in the design of Rust; requiring type annotations +in function definitions means the compiler almost never needs you to use them +elsewhere in the code in order to figure out what you mean. + +When you want a function to have multiple arguments, just separate them inside +the function signature with commas, like this: + +```text +fn NAME(PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE...) { +``` + +And just like a `let` declaration with multiple patterns, a type must be +applied to each pattern separately. To demonstrate, here’s a full example of a +function with multiple arguments: + +```rust +fn main() { + another_function(5, 6); +} + +fn another_function(x: i32, y: i32) { + println!("The value of x is: {}", x); + println!("The value of y is: {}", y); +} +``` + +In this example, we make a function with two arguments. In this case, both are +`i32`s. If your function has multiple arguments, they don’t need to be the same +type, but they just happen to be in this example. Our function then prints out +the values of both of its arguments. + +Let’s try out this code. Replace the program currently in your `function` +project's `main.rs` file with the example above, and run it as follows: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +The value of x is: 5 +The value of y is: 6 +``` + +Since `5` is passed as the `x` argument and `6` is passed as the `y` argument, +the two strings are printed with these values. + +### Variable Bindings as Arguments + +It's also possible to create bindings and pass them in as arguments in Rust. +For example: + +```rust +fn main() { + let a = 5; + let b = 6; + + another_function(a, b); +} + +fn another_function(x: i32, y: i32) { + println!("The value of x is: {}", x); + println!("The value of y is: {}", y); +} +``` + +Instead of passing `5` and `6` directly, this first creates two bindings +containing the values, and passes those bindings instead. When you run this, +you'll find that it has the same effect as just using integers: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +The value of x is: 5 +The value of y is: 6 +``` + +Note that our bindings are called `a` and `b`, yet inside the function, we +refer to them by the names in the signature, `x` and `y`. Inside a function, +its parameters are in scope but the names of the bindings we passed as +parameters are not, so we need to use the parameter names within the function +block. Bindings passed as parameters don’t need to have the same names as the +arguments. + +### Function Bodies + +Function bodies are made up of a series of statements ending in an optional +expression. So far, we've only seen functions without an ending expression, but +we have seen expressions as parts of statements. Since Rust is an +expression-based language, this is an important distinction to understand. +Other languages don't have the same distinctions, so let's look at what +statements and expressions are and how their differences affect the bodies of +functions. + +#### Statements and Expressions + + + + +We've already been using both statements and expressions. *Statements* are +instructions that perform some action and do not return a value. *Expressions* +evaluate to a resulting value. Let's look at some examples. + +`Let` bindings are statements. They instruct the program to create a binding +name and assign a value to it. `let y = 6;` in this example is a statement: + +```rust +fn main() { + let y = 6; +} +``` + +Function definitions are also statements-- so the entire previous example is a +statement as well. + +Statements do not return values themselves. Therefore, you can’t assign a `let` +binding to another binding, as this code tries to do: + +```rust,ignore +fn main() { + let x = (let y = 6); +} +``` + +If we were to run this program, we’d get an error like this: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) +src/main.rs:2:14: 2:17 error: expected identifier, found keyword `let` +src/main.rs:2 let x = (let y = 6); + ^~~ +src/main.rs:2:18: 2:19 error: expected one of `!`, `)`, `,`, `.`, `::`, `{`, or an operator, found `y` +src/main.rs:2 let x = (let y = 6); + ^ +Could not compile `functions`. +``` + + + + +The `let y = 6` statement does not return a value, so there isn't anything for +`x` to bind to. This is different than in other languages like C and Ruby where +the assignment returns the value of the assignment. In those languages, you +could write `x = y = 6` and have both `x` and `y` have the value `6`, but that +is not the case in Rust. + +Expressions are most of the rest of the code that you will write in Rust. +Consider a simple math operation, like this: + +```rust,ignore +5 + 6 +``` + +This is an expression, and evaluating it results in the value `11`. Expressions +can be part of statements-- in the previous example that had the statement `let +y = 6;`, `6` is an expression that evaluates to the value `6`. Calling a +function is an expression. Calling a macro is an expression. The block that we +use to create new scopes, `{}`, is an expression, for example: + +```rust +fn main() { + let x = 5; + + let y = { + let x = 3; + x + 1 + }; + + println!("The value of y is: {}", y); +} +``` + +The expression: + +```rust,ignore +{ + let x = 3; + x + 1 +} +``` + +is a block that, in this case, gets evaluated to `4`, which then gets bound to +`y` as part of the `let` statement. + +Note that the line containing `x + 1` does not have a semicolon at the end like +most of the lines we've seen up until now have had. This is the most important +distinction between expressions and statements to remember: statements end in +semicolons while expressions do not. If you add a semicolon to the end of an +expression, that will turn it into a statement, which will then not return a +value. Keep this in mind as we explore function return values and expressions. + + + +### Functions with Return Values + + + + +Functions can return values back to the code that calls them. In Rust, the +"return value of the function” is synonymous with “the value of the final +expression in the block of the body of a function.” A function that returns a +value looks like this: + + + +```text +fn NAME(PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE...) -> TYPE { + STATEMENT* + EXPRESSION +} +``` + +The `*` by `STATEMENT` indicates "zero or more", meaning we can have any number +of statements inside the function body block, ending with an expression since +we are returning a value. + +In Rust, we don’t name return values, but we do declare their type, after an +arrow (`->`). Here’s a sample program to illustrate this concept: + +```rust +fn main() { + let x = five(); + + println!("The value of x is: {}", x); +} + +fn five() -> i32 { + 5 +} +``` + +There are no function calls, macros, or even `let` statements in the `five()` +function-- just the number `5` by itself. That's a perfectly valid function in +Rust. Note the function's return type, too. Try running this code, and the +output should look like this: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +The value of x is: 5 +``` + +The `5` in `five()` is actually the function's return value, which is why the +return type is `i32`. Let’s examine this in more detail. There are two +important bits. First, the line `let x = five();` in `main()` shows that we can +use the return value of a function to initialize a binding. + +Because the function `five()` returns a `5`, that line is the same as saying: + +```rust +let x = 5; +``` + +The second interesting bit is the `five()` function itself. It requires no +arguments and defines the type of the return, but the body of the function is a +lonely `5` with no semicolon because it is an expression whose value we want to +return. Let's look at another example: + +```rust +fn main() { + let x = plus_one(5); + + println!("The value of x is: {}", x); +} + +fn plus_one(x: i32) -> i32 { + x + 1 +} +``` + +Running this code will print `The value of x is: 6`. What happens if we put a +semicolon at the end of the line containing `x + 1`, changing it from an +expression to a statement? + +```rust,ignore +fn main() { + let x = plus_one(5); + + println!("The value of x is: {}", x); +} + +fn plus_one(x: i32) -> i32 { + x + 1; +} +``` + +Running this code gives an error, as follows: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) +src/main.rs:7:1: 9:2 error: not all control paths return a value [E0269] +src/main.rs:7 fn plus_one(x: i32) -> i32 { +src/main.rs:8 x + 1; +src/main.rs:9 } +src/main.rs:7:1: 9:2 help: run `rustc --explain E0269` to see a detailed explanation +src/main.rs:8:10: 8:11 help: consider removing this semicolon: +src/main.rs:8 x + 1; + ^ +error: aborting due to previous error +Could not compile `functions`. +``` + +The main error message, "not all control paths return a value," reveals the +core of the issue with this code. The definition of the function `plus_one` +says that it will return an `i32`, but statements don’t evaluate to a value. +Therefore, nothing is returned, which contradicts the function definition and +results in an error. In this output, Rust gives an option to rectify this: it +suggests removing the semicolon, which would fix the error. + +#### Returning Multiple Values + +By default, functions can only return single values. There’s a trick, however +to get them to return multiple values. Remember how we used `()`s to create +complex bindings in the "Creating Multiple Bindings" section on page XX? + +```rust +fn main() { + let (x, y) = (5, 6); +} +``` + +Parentheses used in this way form a *tuple*-- a collection of elements that +isn't assigned a name. Tuples are also a basic data type in Rust, and we'll +cover them in detail in the "Tuples" section later in this chapter. For our +purposes now, we can use tuples to return multiple values from functions, as so: + +```rust +fn main() { + let (x, y) = two_numbers(); + + println!("The value of x is: {}", x); + println!("The value of y is: {}", y); +} + +fn two_numbers() -> (i32, i32) { + (5, 6) +} +``` + +Running this will give us the values: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +The value of x is: 5 +The value of y is: 6 +``` + +Let's look at this more closely. First, we're assigning the return value of +calling `two_numbers()` to `x` and `y`. In the function signature, we would say +in plain English that the return type `(i32, i32)` translates to “a tuple with +two `i32`s in it". These two types are then applied to the tuple to be returned +by the function block. In this case, that tuple contains the values `5` and +`6`. This tuple is returned, and assigned to `x` and `y`. + +See how all these bits fit together? We call this behavior of `let` +‘destructuring’, because it takes the structure of the expression that follows +the `=` and takes it apart. + + + + + From 6086b96384539b172174ed14c1157e50bb0478c2 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 3 Jul 2016 14:58:06 -0400 Subject: [PATCH 038/204] Backport changes to comments section --- src/ch03-06-comments.md | 68 +++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/src/ch03-06-comments.md b/src/ch03-06-comments.md index 7a96ae381b..2607ad225d 100644 --- a/src/ch03-06-comments.md +++ b/src/ch03-06-comments.md @@ -1,17 +1,18 @@ -# Comments +## Comments -We strive to make our programs easy to understand, but sometimes, some extra -explanation is warranted. We can leave notes in our source code that the -compiler will ignore. These notes are called ‘comments’. +All programmers strive to make their code easy to understand, but sometimes +some extra explanation is warranted. In these cases, we leave notes in our +source code that the compiler will ignore. These notes are called *comments*. -Here’s a comment: +Here’s a simple comment: ```rust // Hello, world. ``` -Comments start with two slashes, and last until the end of the line. Larger -comments will need more lines: +In Rust, comments must start with two slashes, and will last until the end of +the line. For comments that extend beyond a single line, you'll need to include +`//` on each line, like this: ```rust // So we’re doing something complicated here, long enough that we need @@ -19,7 +20,7 @@ comments will need more lines: // explain what’s going on. ``` -Comments can also go at the end of lines: +Comments can also be placed at the end of lines of code: ```rust fn main() { @@ -27,7 +28,7 @@ fn main() { } ``` -But you’ll more often see them above: +But you’ll more often see them above, like so: ```rust fn main() { @@ -38,42 +39,63 @@ fn main() { That’s all there is to it. Comments are not particularly complicated. -## Documentation comments +### Documentation Comments -However, Rust has another kind of comment: a documentation comment. These -comments don’t affect the way that the code works, but they do work with Rust’s -tools. More specifically, the `rustdoc` tool that comes with Rust reads -documentation comments and produces HTML documentation from them. + + -Documentation comments use an extra slash: +Rust has another kind of comment: a *documentation comment*. These comments +don’t affect the way that the code works, but they do work with Rust’s tools. +More specifically, the `rustdoc` tool can read documentation comments and +produce HTML documentation from them. This documentation's intended audience is +usually people who are using your code, so that they know how to interact with +it. Regular comments won't be shown in `rustdoc` generated HTML, so their +intended audience is people who are reading and editing your code. + +Documentation comments use an extra slash, like this: ```rust /// The foo function doesn’t really do much. fn foo() { + } -/// We also can use -/// multiple comments here too, -/// like we did before +/// Documentation comments can use +/// multiple line comments too, +/// like we did before. fn bar() { + } ``` -This comment would then be interpreted by `rustdoc` as documenting the thing -that follows it: `foo()` and `bar()`. +The `rustdoc` tool would interpret each comment in this example as documenting +the thing that follows it. The first comment would be used to document the +`foo()` function, and the second comment would document the `bar()` function. Because documentation comments have semantic meaning to `rustdoc`, the compiler will pay attention to the placement of your documentation comments. For -example, a program with only this: +example, a program containing only this: ```rust,ignore /// What am I documenting? ``` -Will give a compiler error: +Will give the following compiler error: -```text +```bash src/main.rs:1:1: 1:27 error: expected item after doc comment src/main.rs:1 /// What am I documenting? ^~~~~~~~~~~~~~~~~~~~~~~~~~ ``` + +This happens because Rust expects a document comment to be associated with +whatever code comes directly after it, so it sees that a document comment alone +must be a mistake. + + From ff08e0608d4cafe5875f574f7edf0a1e84dbbc76 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 3 Jul 2016 14:59:52 -0400 Subject: [PATCH 039/204] Backport changes to control flow --- src/SUMMARY.md | 3 +- src/ch03-07-control-flow.md | 503 ++++++++++++++++++++++++++++++++++++ src/ch03-07-if.md | 214 --------------- src/ch03-08-loops.md | 197 -------------- 4 files changed, 504 insertions(+), 413 deletions(-) create mode 100644 src/ch03-07-control-flow.md delete mode 100644 src/ch03-07-if.md delete mode 100644 src/ch03-08-loops.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 7221a432c0..b7b213011b 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -13,8 +13,7 @@ - [Data Types in Rust](ch03-04-data-types-in-rust.md) - [How Functions Work in Rust](ch03-05-how-functions-work-in-rust.md) - [Comments](ch03-06-comments.md) - - [Control flow with `if`](ch03-07-if.md) - - [Loops](ch03-08-loops.md) + - [Control flow](ch03-07-control-flow.md) - [Understanding Ownership](ch04-01-understanding-ownership.md) - [Ownership](ch04-02-ownership.md) diff --git a/src/ch03-07-control-flow.md b/src/ch03-07-control-flow.md new file mode 100644 index 0000000000..c5d330ca34 --- /dev/null +++ b/src/ch03-07-control-flow.md @@ -0,0 +1,503 @@ +## Control Flow + + + +### `if` Statements + +> Two roads diverged in a yellow wood, +> And sorry I could not travel both +> And be one traveler, long I stood +> And looked down one as far as I could +> To where it bent in the undergrowth; +> +> - Robert Frost, “The Road Not Taken” + +In Rust, as in most programming languages, an `if` expression allows us to +branch our code depending on conditions. We provide a condition, and then say, +`if` this condition is met, then run this block of code. If the condition is +not met, do not run this block of code. + +Let’s make a new project to explore `if`. Navigate to your projects directory, +and use Cargo to make a new project called `branches`: + +```bash +$ cargo new --bin branches +$ cd branches +``` + +Write this sample program using `if` and save it in the *branches* directory in +`src/main.rs`: + +```rust +fn main() { + let condition = true; + + if condition { + println!("condition was true"); + } +} +``` + +The `condition` variable is a boolean; here, it's set to true. All `if` +statements start with `if`, which is followed by a condition. The block of code +we want to execute if the condition is true goes immediately after the +condition, inside curly braces. These blocks are sometimes called ‘arms’. + +Try running this code, and you should see output like this: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +condition was true +``` + +Let’s try changing the value of `condition` to `false` as follows to see what +happens: + +```rust + let condition = false; +``` + +Run the program again, and look at the output: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +``` + +Nothing was output, because the condition was false and the `if` block was not +run. + +We can optionally also include an `else` statement, which gives the program a +block of code to execute should `condition` evaluate to false. + +```rust +fn main() { + let condition = false; + + if condition { + println!("condition was true"); + } else { + println!("condition was false"); + } +} +``` + +If we run this program, the output will look like: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +condition was false +``` + +This time, because `condition` was false and we have an `else` block, the +`else` block was executed. + + + + +It’s also worth noting that `condition` here _must_ be a `bool`. To see what +happens if the condition isn't a `bool`, try running this code: + +```rust,ignore +fn main() { + let condition = 5; + + if condition { + println!("condition was five"); + } +} +``` + +The `condition` variable is assigned a value of `5` this time, and Rust will +complain about it: + +```bash + Compiling branches v0.1.0 (file:///projects/branches) +src/main.rs:4:8: 4:17 error: mismatched types: + expected `bool`, + found `_` +(expected bool, + found integral variable) [E0308] +src/main.rs:4 if condition { + ^~~~~~~~~ +src/main.rs:4:8: 4:17 help: run `rustc --explain E0308` to see a detailed explanation +error: aborting due to previous error +Could not compile `branches`. +``` + +The error tells us that Rust expected a `bool`, but got an integer. Rust will +not automatically try to convert non-boolean types to a boolean here, unlike +languages like Ruby or JavaScript. We must be explicit and always give `if` a +`boolean` as its condition. + + + + +#### Multiple Conditions with `else if` + +We can have multiple coniditions by combining `if` and `else` in an `else if` +expression. For example: + +```rust +fn main() { + let number = 5; + + if number == 3 { + println!("condition was 3"); + } else if number == 4 { + println!("condition was 4"); + } else if number == 5 { + println!("condition was 5"); + } else { + println!("condition was something else"); + } +} +``` + +This program has four possible paths it can take. If you try running it, you +should see output like this: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +condition was 5 +``` + +When this program executes, it will check each `if` expression in turn and +execute the first body for which the condition holds true. + +Using too many `else if` expressions can clutter your code, so if you find +yourself with more than one, you may want to look at refactoring your code. In +Chapter XX, we'll talk about a powerful Rust branching construct called `match` +for these cases. + +#### Using `if` in a Binding + +The last detail you need to learn about `if` is that it’s an expression. That +means that we can use it on the right hand side of a `let` binding, for +instance: + +```rust +fn main() { + let condition = true; + let number = if condition { + 5 + } else { + 6 + }; + + println!("The value of number is: {}", number); +} +``` + +The `number` variable will be bound to a value based on the outcome of the `if` +expression. Let’s run this to see what happens: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +The value of number is: 5 +``` + +Remember, blocks of code evaluate to the last expression in them, and numbers +by themselves are also expressions. In this case, the value of the whole `if` +expression depends on which block of code executes. This means that the value +in both arms of the `if` must be the same type; in the previous example, they +were both `i32` integers. But what happens if the types are mismatched, as in +the following example? + +```rust,ignore +fn main() { + let condition = true; + + let number = if condition { + 5 + } else { + "six" + }; + + println!("The value of number is: {}", number); +} +``` + +The expression in one block of the `if` statement, is an integer and the +expresion in the other block is a string. If we try to run this, we’ll get an +error: + +```bash + Compiling branches v0.1.0 (file:///projects/branches) +src/main.rs:4:18: 8:6 error: if and else have incompatible types: + expected `_`, + found `&‘static str` +(expected integral variable, + found &-ptr) [E0308] +src/main.rs:4 let number = if condition { +src/main.rs:5 5 +src/main.rs:6 } else { +src/main.rs:7 "six" +src/main.rs:8 }; +src/main.rs:4:18: 8:6 help: run `rustc --explain E0308` to see a detailed explanation +error: aborting due to previous error +Could not compile `branches`. +``` + +The `if` and `else` arms have value types that are incompatible, and Rust tells +us exactly where to find the problem in our program. This can’t work, because +variable bindings must have a single type. + +### Repetition with Loops + +It’s often useful to be able to execute a block of code more than one time. For +this, Rust has several constructs called *loops*. A loop runs through the code +inside it to the end and then starts immediately back at the beginning. To try +out loops, let’s make a new project. Navigate to your *projects* folder and use +Cargo to make a new project: + +```bash +$ cargo new --bin loops +$ cd loops +``` + +There are three kinds of loops in Rust: `loop`, `while`, and `for`. Let’s dig +in. + +#### Repeating Code with `loop` + + + + +The `loop` keyword tells Rust to execute a block of code over and over again +forever, or until we explicitly tell it to stop. + +For an example, change the *src/main.rs* file in your *loops* directory to look +like this: + +```rust,ignore +fn main() { + loop { + println!("again!"); + } +} +``` + +If we run this program, we’ll see `again!` printed over and over continuously +until we stop the program manually. Most terminals support a keyboard shortcut, +`control-c`, to halt a program stuck in a continual loop. Give it a try: + +```bash +$ cargo run + Compiling loops v0.1.0 (file:///projects/loops) + Running `target/debug/loops` +again! +again! +again! +again! +^Cagain! +``` + + + +That `^C` there is where I hit `control-c`. Fortunately, Rust provides another, +more reliable way to break out of a loop. We can place the `break` keyword +within the loop to tell the program when to stop executing the loop. Try this +version of the program out: + +```rust +fn main() { + loop { + println!("once!"); + break; + } +} +``` + +If you run this program, you’ll see that it only executes one time: + +```bash +$ cargo run + Compiling loops v0.1.0 (file:///projects/loops) + Running `target/debug/loops` +once! +``` + +When a Rust program hits a `break` statement, it will exit the current loop. +This on its own is not very useful; if we wanted to print somtheing just once, +we wouldn't put it in a loop. This is where conditions come in again. + +#### Conditional Loops With `while` + +To make `break` useful, we need to give our program a condition. While the +condition is true, the loop runs. When the condition ceases to be true, the +`break` code runs, stopping the loop. + +Try this example: + +```rust +fn main() { + let mut number = 3; + + loop { + if number != 0 { + println!("{}!", number); + + number = number - 1; + } else { + break; + } + } + + println!("LIFTOFF!!!"); +} +``` + +If we run this, we’ll get: + +```bash + Compiling loops v0.1.0 (file:///projects/loops) + Running `target/debug/loops` +3! +2! +1! +LIFTOFF!!! +``` + +This program loops three times, counting down each time. Finally, after the +loop, it prints another message, then exits. + +The core of this example is in the combination of `loop`, `if`, `else`, and +`break`. + + + + + +We want to `loop`, but only while some sort of condition is true. As soon as it +isn't, we want to `break` out of the loop. This pattern is so common that Rust +has a more efficient language construct for it, called a `while` loop. Here's +the same example, but using `while` instead: + +```rust +fn main() { + let mut number = 3; + + while number != 0 { + println!("{}!", number); + + number = number - 1; + } + + println!("LIFTOFF!!!"); +} +``` + +This gets rid of a lot of nesting, and it's more clear. While a condition +holds, run this code; otherwise, do nothing. + +#### Looping Though a Collection with `for` + +We can use this `while` construct to loop over the elements of a collection, +like an array. For example: + +```rust +fn main() { + let a = [10, 20, 30, 40, 50]; + let mut index = 0; + + while index < 5 { + println!("the value is: {}", a[index]); + + index = index + 1; + } +} +``` + + + +Here, we're counting up through the elements in the array. We start at index 0, +then loop until we hit the final index of our array (that is, when `index < 5` +is no longer true). Running this will print out every element of the array: + +```bash +$ cargo run + Compiling loops v0.1.0 (file:///projects/loops) + Running `target/debug/loops` +the value is: 10 +the value is: 20 +the value is: 30 +the value is: 40 +the value is: 50 +``` + +All five array values appear in the terminal, as expected. Even though `index` +will reach a value of `6` at some point, the loop stops executing before trying +to fetch a sixth value from the array. + +This approach is error-prone, though; we could cause our program to panic by +getting the index length incorrect. It's also slow, as the compiler needs to +perform the conditional check on every element on every iteration through the +loop. + +As a more efficient alternative, we can use a `for` loop. A `for` loop looks +something like this: + +```rust +fn main() { + let a = [10, 20, 30, 40, 50]; + + for element in a.iter() { + println!("the value is: {}", element); + } +} +``` + +** NOTE: see [https://github.com/rust-lang/rust/issues/25725#issuecomment-166365658](https://github.com/rust-lang/rust/issues/25725#issuecomment-166365658), we may want to change this ** + + +If we run this, we'll see the same output as the previous example. + + + + + +** I'm going to leave it at this for now until we decide how we want to do it** + + + + diff --git a/src/ch03-07-if.md b/src/ch03-07-if.md deleted file mode 100644 index 270491b724..0000000000 --- a/src/ch03-07-if.md +++ /dev/null @@ -1,214 +0,0 @@ -# Control flow with `if` - -> Two roads diverged in a yellow wood, -> And sorry I could not travel both -> And be one traveler, long I stood -> And looked down one as far as I could -> To where it bent in the undergrowth; -> -> - Robert Frost, “The Road Not Taken” - -In Rust, there are a few ways to cause our code to branch. The most fundamental -way is by using `if`. An `if` expression gives us two paths forward, and asks -the question, “Which one should I take?” - -Let’s make a new project to explore `if`. Navigate to your projects directory, -and use Cargo to make a new project called `branches`: - -```bash -$ cargo new --bin branches -$ cd branches -``` - -Here’s a sample program using `if`: - -```rust -fn main() { - let condition = true; - - if condition { - println!("condition was true"); - } else { - println!("condition was false"); - } -} -``` - -Let's try running it: - -```bash -$ cargo run - Compiling branches v0.1.0 (file:///projects/branches) - Running `target/debug/branches` -condition was true -``` - -We can change the value of `condition`: - -```rust - let condition = false; -``` - -And then run it again: - -```bash -$ cargo run - Compiling branches v0.1.0 (file:///projects/branches) - Running `target/debug/branches` -condition was false -``` - -This is the very basic structure of `if`: _if_ the condition is true, then -execute some code. If it’s not true, then execute some other code, after -`else`. - -An `else` is not required: - -```rust -fn main() { - let condition = false; - - if condition { - println!("condition was true"); - } -} -``` - -In this case, nothing is printed. - -It’s also worth noting that `condition` here _must_ be a `bool`. Let’s try an -example with something else: - -```rust,ignore -fn main() { - let condition = 5; - - if condition { - println!("condition was five"); - } -} -``` - -If we try to run this program, Rust will complain: - -```bash - Compiling branches v0.1.0 (file:///projects/branches) -src/main.rs:4:8: 4:17 error: mismatched types: - expected `bool`, - found `_` -(expected bool, - found integral variable) [E0308] -src/main.rs:4 if condition { - ^~~~~~~~~ -src/main.rs:4:8: 4:17 help: run `rustc --explain E0308` to see a detailed explanation -error: aborting due to previous error -Could not compile `branches`. -``` - -We expected a `bool`, but got an integer. Rust will not automatically try to convert non-boolean types to a boolean here. We must be explicit. - -## `else if` - -We can make multiple decisions by combining `if` and `else` in another way: - -```rust -fn main() { - let number = 5; - - if number == 3 { - println!("condition was 3"); - } else if number == 4 { - println!("condition was 4"); - } else if number == 5 { - println!("condition was 5"); - } else { - println!("condition was something else"); - } -} -``` - -Let's try running it: - -```bash -$ cargo run - Compiling branches v0.1.0 (file:///projects/branches) - Running `target/debug/branches` -condition was 5 -``` - -When this program executes, it will check each `if` in turn, and execute the -first body for which the condition holds true. - -Using a single `else if` can be okay, but if you find yourself with more than one, -you may want to refactor your code. Rust has a more powerful branching construct -called `match` for these cases. We'll cover it later, when we talk about `enums`. - -## `if` as an expression - -There’s one last detail we need to learn about `if`: it’s an expression. That means -that we can use it on the right hand side of a `let` binding, for instance: - -```rust -fn main() { - let condition = true; - - let number = if condition { - 5 - } else { - 6 - }; - - println!("The value of number is: {}", number); -} -``` - -Let’s run this: - -```bash -$ cargo run - Compiling branches v0.1.0 (file:///projects/branches) - Running `target/debug/branches` -The value of number is: 5 -``` - -Remember, blocks of code evaluate to the last expression in them. And numbers -by themselves are also expressions. So in this case, the value of the whole -`if` expression depends on which block of code executes. - -There’s another small detail involved here: this means that if you use `if` -in this way, both arms of the `if` must be the same type. This doesn’t work: - -```rust,ignore -fn main() { - let condition = true; - - let number = if condition { - 5 - } else { - "six" - }; - - println!("The value of number is: {}", number); -} -``` - -If we try to run this, we’ll get an error: - -```bash - Compiling branches v0.1.0 (file:///projects/branches) -src/main.rs:4:18: 8:6 error: if and else have incompatible types: - expected `_`, - found `&‘static str` -(expected integral variable, - found &-ptr) [E0308] -src/main.rs:4 let number = if condition { -src/main.rs:5 5 -src/main.rs:6 } else { -src/main.rs:7 "six" -src/main.rs:8 }; -src/main.rs:4:18: 8:6 help: run `rustc --explain E0308` to see a detailed explanation -error: aborting due to previous error -Could not compile `branches`. -``` - -`if` and `else` have incompatible types. This can’t work. diff --git a/src/ch03-08-loops.md b/src/ch03-08-loops.md deleted file mode 100644 index 7c73efc246..0000000000 --- a/src/ch03-08-loops.md +++ /dev/null @@ -1,197 +0,0 @@ -# Loops - -It’s often quite useful to be able to execute a block of code more than one -time. For this, we have several constructs, called ‘loops’. - -To try out loops, let’s make a new project. Navigate to your projects folder -and use Cargo to make a new one: - -```bash -$ cargo new --bin loops -$ cd loops -``` - -There are three kinds of loops in Rust: `loop`, `while`, and `for`. Let’s dig -in. - -## `loop` - -The `loop` keyword is very straightforward: it executes a block of code over -and over and over and over and over and over forever. Change your `src/main.rs` -file to look like this: - -```rust,ignore -fn main() { - loop { - println!("again!"); - } -} -``` - -If we run this program, we’ll see ‘`again!`’ printed over and over again. So -how does our program end? It doesn’t, until we kill it. Most terminals support -a keyboard shortcut, ‘control-c’, to stop a runaway program. Give it a try: - -```bash -$ cargo run - Compiling loops v0.1.0 (file:///projects/loops) - Running `target/debug/loops` -again! -again! -again! -again! -^Cagain! -``` - -That `^C` there is where I hit control-c. - -That’s a lot of trouble though! Luckily, there’s a way to break an infinite `loop`. - -### Breaking out of a loop - -The `break` keyword will allow us to quit looping. Try this version out: - -```rust -fn main() { - loop { - println!("once!"); - break; - } -} -``` - -If you run this program with `cargo run`, you’ll see that it only executes one -time: - -```bash -$ cargo run - Compiling loops v0.1.0 (file:///projects/loops) - Running `target/debug/loops` -once! -``` - -When a Rust program hits a `break` statement, it will exit the current loop. - -## `while` - -What if we took `loop`, `break`, and `if`, and put them together? Something -like this: - -```rust -fn main() { - let mut number = 3; - - loop { - if number != 0 { - println!("{}!", number); - - number = number - 1; - } else { - break; - } - - } - - println!("LIFTOFF!!!"); -} -``` - -If we run this, we’ll get some output: - -```bash - Compiling loops v0.1.0 (file:///projects/loops) - Running `target/debug/loops` -3! -2! -1! -LIFTOFF!!! -``` - -The core of this example is in the combination of these three constructs: - -```rust,ignore - loop { - if number != 0 { - // do stuff - } else { - break; - } -``` - -We want to `loop`, but only while some sort of condition is true. As soon as it -isn't, we want to `break` out of the loop. - -This pattern is so common that we have a language construct for it: `while`. -Here's the same example, but using `while` instead: - -```rust -fn main() { - let mut number = 3; - while number != 0 { - println!("{}!", number); - - number = number - 1; - } - - println!("LIFTOFF!!!"); -} -``` - -This lets us get rid of a lot of nesting, and is more clear: while a condition holds, -run this code. - -## `for` - -We can use this `while` construct to loop over the elements of a collection, like an -array: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; - let mut index = 0; - - while index < 5 { - println!("the value is is: {}", a[index]); - - index = index + 1; - } -} -``` - -Running this will print out every element of the array: - -```bash -$ cargo run - Compiling loops v0.1.0 (file:///projects/loops) - Running `target/debug/loops` -the value is: 1 -the value is: 2 -the value is: 3 -the value is: 4 -the value is: 5 -``` - -Here, we're counting up instead of down: we start at zero, then loop until we -hit the final index of our array. - -This approach is error-prone, though. If we get the index length incorrect, we -will end up causing a `panic!`. This is also slow, as the compiler needs to do -that check on every element on every iteration through the loop. - -Instead, we can use our last kind of loop: the `for` loop. It looks like this: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; - - for element in a.iter() { - println!("the value is: {}", element); - } -} -``` - -** NOTE: see [https://github.com/rust-lang/rust/issues/25725#issuecomment-166365658](https://github.com/rust-lang/rust/issues/25725#issuecomment-166365658), we may want to change this ** - -If we run this, we'll see the same output as the previous example. - -** I'm going to leave it at this for now until we decide how we want to do it** From fdd28f7e66fa8d78bd248f90e5c69c2611bb8c7c Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 3 Jul 2016 15:15:21 -0400 Subject: [PATCH 040/204] Resolve comments in Anatomy of a Rust Program --- src/ch03-02-anatomy-of-a-rust-program.md | 97 ++++-------------------- 1 file changed, 16 insertions(+), 81 deletions(-) diff --git a/src/ch03-02-anatomy-of-a-rust-program.md b/src/ch03-02-anatomy-of-a-rust-program.md index ce63b4561a..a1d270d5e4 100644 --- a/src/ch03-02-anatomy-of-a-rust-program.md +++ b/src/ch03-02-anatomy-of-a-rust-program.md @@ -7,13 +7,6 @@ variable, and how to print text to the terminal. ### Keywords - - First, keep in mind that the Rust language has a set of *keywords* that have been reserved for use by the language only. This means you cannot use these words as names of variables or functions, for example. Most of these have @@ -78,10 +71,10 @@ The keywords are: ### A Simple Program that Binds a Variable -Let’s start with a short example that binds a value to a variable, and then -uses that in a sentence that we'll print to the screen. First, we’ll generate a -new project with Cargo. Open a terminal, and navigate to the directory you want -to store your projects in. From there, generate a new project: +Let’s start with a short example that binds a value to a variable and then uses +that in a sentence that we'll print to the screen. First, we’ll generate a new +project with Cargo. Open a terminal, and navigate to the directory you want to +store your projects in. From there, generate a new project: ```bash $ cargo new --bin bindings @@ -124,33 +117,18 @@ down, line by line. #### Starting a Program with the main() Function -Most Rust programs open with the same first line as this one from our example -program: - +Many Rust programs will contain the same function that our example program does: ```rust,ignore fn main() { ``` -The `main()` function is the entry point of every Rust program. It doesn’t have -to be at the very beginning of our source code, but it will be the first bit of code that -runs when we execute our program. We’ll talk more about functions in the next -section, but for now, just know that ```main()``` is where our program begins. -The opening curly brace (`{`) indicates the start of the function’s body. +The `main()` function is the entry point of every executable Rust program. It +doesn’t have to be at the very beginning of our source code, but it will be the +first bit of code that runs when we execute our program. We’ll talk more about +functions in the next section, but for now, just know that `main()` is +where our program begins. The opening curly brace (`{`) indicates the start of +the function’s body. #### Binding a Variable with `let` @@ -167,10 +145,10 @@ Basic `let` statements take the following form: let NAME = EXPRESSION; ``` -A `let` statement first evaluates the `EXPRESSION`, and then binds the -resulting value to `NAME` to give us a variable to use later in the program. -Notice the semicolon at the end of the statement, too. As in many other -programming languages, statements in Rust must end with a semicolon. +A `let` statement first evaluates the `EXPRESSION` and then binds the resulting +value to `NAME` to give us a variable to use later in the program. Notice the +semicolon at the end of the statement, too. As in many other programming +languages, statements in Rust must end with a semicolon. In this simple example, the expression already is a value, but we could achieve the same result like this: @@ -194,37 +172,6 @@ expression that works on values in your program instead of characters in text. A name like `x` is a particularly humble form of pattern; it will always match and gets all the parts of the expression as its value. Patterns are a big part of Rust, and we’ll see more complex and powerful patterns as we go along. - #### Printing to the Screen with a Macro @@ -236,7 +183,7 @@ The next line of our program is: The `println!` command is a *macro* that prints the text passed to it to the screen. Macros are indicated with the `!` character at the end of their name. -In Chapter , you'll learn more about the details of macros and how to +In Chapter XX, you'll learn more about the details of macros and how to write macros yourself, but for now we'll just be using macros provided by the standard Rust library. @@ -250,18 +197,6 @@ generated for us called the `println!` macro with one argument (the string with the same number of arguments that their definition specifies, but macros have different rules that allow them to take different numbers of arguments. - - The `println!` macro only requires one argument: a format string. You can add optional arguments inside this format string by using the special text `{}`. Each instance of `{}` corresponds to an additional argument. Here’s an example: From ef9741ac168455e379b214d5c0ba287914f58f67 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 3 Jul 2016 17:55:28 -0400 Subject: [PATCH 041/204] Resolve comments and make some more edits in variable bindings --- src/ch03-03-variable-bindings-in-detail.md | 164 +++++---------------- 1 file changed, 38 insertions(+), 126 deletions(-) diff --git a/src/ch03-03-variable-bindings-in-detail.md b/src/ch03-03-variable-bindings-in-detail.md index efb6461024..25678fc2fe 100644 --- a/src/ch03-03-variable-bindings-in-detail.md +++ b/src/ch03-03-variable-bindings-in-detail.md @@ -11,9 +11,6 @@ The previous example program just bound one variable, but it's also possible to create multiple variable bindings in one go. Let’s try a more complex example, creating two variable bindings at once. Change your example program to this: - - ```rust fn main() { let (x, y) = (5, 6); @@ -46,7 +43,7 @@ fn main() { } ``` -In simple cases like this, where we are only binding two variables, two `let` +In simple cases like this where we are only binding two variables, two `let` statements may be clearer in the code, but when you're creating many multiple bindings, it's useful to be able to do so all at once. Deciding which technique to use is mostly a judgement call, and as you become more proficient in Rust, @@ -61,9 +58,7 @@ after the `let` statement. To try this out, write the following program: ```rust fn main() { let x; - x = 5; - println!("The value of x is: {}", x); } ``` @@ -77,7 +72,7 @@ $ cargo run The value of x is: 5 ``` -As you can see, this works just like the previous program, in which we assigned +As you can see, this works just like the previous program in which we assigned an initial value. This raises an interesting question: what happens if we try to print out a @@ -87,9 +82,7 @@ like the following: ```rust,ignore fn main() { let x; - println!("The value of x is: {}", x); - x = 5; } ``` @@ -117,7 +110,7 @@ instead it requests that you assign a value to the variable `x`. This is our first example of the compiler helping us find an error in our program. Different programming languages have different ways of approaching this problem. Some languages will always initialize values with some sort of -default. Other languages leave the value uninitialized, and make no promises +default. Other languages leave the value uninitialized and make no promises about what happens if you try to use something before initialization. Rust responds with an error to prod the programmer to declare the value they want. We must initialize any variable before we can use it. @@ -134,10 +127,10 @@ src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed expla ``` This tells us that if we pass the `--explain` flag to `rustc` with the provided -error code, we can see an extended explanation, which will try to explain -common causes of and solutions to that kind of error. Not every error has a -longer explanation, but many do. Here’s the explanation for the `E0381` error -we received previously: +error code, we can see an extended explanation which will try to explain common +causes of and solutions to that kind of error. Not every error has a longer +explanation, but many do. Here’s the explanation for the `E0381` error we +received previously: ```bash $ rustc --explain E0381 @@ -167,9 +160,7 @@ illustrate this: ```rust,ignore fn main() { let x = 5; - x = 6; - println!("The value of x is: {}", x); } ``` @@ -198,11 +189,8 @@ following: ```rust fn main() { let mut x = 5; - println!("The value of x is: {}", x); - x = 6; - println!("The value of x is: {}", x); } ``` @@ -221,16 +209,10 @@ Using `mut`, we change the value that `x` binds to from `5` to `6`. Note, however, that `mut` is part of the pattern in the `let` statement. This becomes more obvious if we try to add mutability to a pattern that binds multiple variables in the same way as we did for a single variable, like this: - ```rust,ignore fn main() { let (mut x, y) = (5, 6); - x = 7; y = 8; } @@ -251,59 +233,11 @@ src/main.rs:2 let (mut x, y) = (5, 6); ``` The way `mut` is used here, the compiler is fine with reassigning the `x` -variable, but not the `y` variable. That's because `mut` only applies to the +variable but not the `y` variable. That's because `mut` only applies to the name that directly follows it, not the whole pattern. For the compiler to allow you to reassign the `y` variable, you'd need to write the pattern as `(mut x, mut y)` instead. - - -One thing to know about mutating bindings: `mut` allows you to mutate _the -binding_, but not _what the name binds to_. In other words, the value is not -what changes, but rather the path between the value and the name. For example: - -```rust -fn main() { - let mut x = 5; - - x = 6; -} -``` - -This does not change the value that `x` is bound to, but creates a new value -(`6`) and changes the binding so that it binds the name `x` to this new value -instead. This subtle but important difference will become more important as -your Rust programs get more complex. - - - ### Variable Binding Scope Another important thing to know about variable bindings is that they are only @@ -312,25 +246,13 @@ binding is declared, and ends with the curly brace that closes the block of code containing that binding. We cannot access bindings "before they come into scope" or "after they go out of scope." Here’s an example to illustrate this: - - ```rust fn main() { - println!("x is not yet in scope"); + println!("x is not yet in scope. Try to print x in this statement to see the compiler error!"); let x = 5; - println!("x is now in scope"); + println!("x is now in scope and its value is {}.", x); println!("In real code, we’d now do a bunch of work."); @@ -347,26 +269,27 @@ braces (we'll look at this more in the next chapter). For example: ```rust fn main() { - println!("x is not yet in scope"); let x = 5; - println!("x is now in scope"); - + println!("x is now in scope and its value is {}.", x); + println!("y is not yet in scope. Try to print y in this statement to see the compiler error!"); println!("Let’s start a new scope!"); { - let y = 5; + println!("y is still not yet in scope..."); + let y = 8; - println!("y is now in scope"); - println!("x is also still in scope"); + println!("NOW y is in scope and its value is {}", y); + println!("x is also still in scope with value {}", x); println!("y will go out of scope now!"); println!("The next curly brace is ending the scope we started."); } - println!("x is still in scope, but y is now out of scope and is not usable"); + println!("x is still in scope: {}", x); + println!("y is now out of scope and is not usable. Try using it here!"); println!("x will go out of scope now! The next curly brace is ending the main function."); } @@ -379,22 +302,12 @@ much more important later as you learn about references in Chapter XX. ### Shadowing Earlier Bindings - - -One final thing about bindings: they can *shadow* previous bindings with the -same name. Shadowing is what happens when you declare two bindings with the -same name. We say that the first binding is ‘shadowed’ by the second, which -means that the second binding's value is what you will see when you use the -variable after the second binding. This can be useful if you’d like to perform -a few transformations on a value, but still leave the binding immutable. For -example: +One final thing about bindings: they can *shadow* previous bindings. Shadowing +is what happens when you declare two bindings with the same name. We say that +the first binding is ‘shadowed’ by the second, which means that the second +binding's value is what you will see when you use the variable after the second +binding. This can be useful if you’d like to perform a few transformations on a +value, but still leave the binding immutable. For example: ```rust fn main() { @@ -408,11 +321,11 @@ fn main() { } ``` -This program first binds `x` to a value of `5`. Then, it shadows `x`, taking -the original value and adding `1` so that the value of `x` is then `6`. The -third `let` statement shadows `x` again, taking the previous value and -multiplying it by `2` to give `x` a final value of `12`. If you run this, it -will output: +This program first binds `x` to a value of `5`. Then, it shadows `x` by saying +`let x =` again, taking the original value and adding `1` so that the value of +`x` is then `6`. The third `let` statement also shadows `x`, taking the +previous value and multiplying it by `2` to give `x` a final value of `12`. If +you run this, it will output: ```bash $ cargo run @@ -422,8 +335,8 @@ The value of x is: 12 ``` Shadowing is useful because it lets us modify `x` without having to make the -variable mutable. This means the compiler will still warn us if we accidentally -try to mutate `x` directly later. For example, say after calculating `12` we +variable mutable. This means the compiler will still keep us from accidentally +trying to mutate `x` directly later. For example, say after calculating `12` we don’t want `x` to be modified again; if we write the program in a mutable style, like this: @@ -443,8 +356,8 @@ fn main() { ``` Rust is happy to let us mutate `x` again, to `15`. A similar program using the -default immutable style, however, will let us know about that accidental -mutation. Here's an example: +default immutable style, however, will prevent us from mutating `x`. Here's an +example: ```rust,ignore fn main() { @@ -476,7 +389,8 @@ error: aborting due to previous error Could not compile `bindings`. ``` -Since we don't want the binding to be mutable, this exactly what should happen. +Since we don't want the binding to be mutable, this is exactly what should +happen. #### Shadowing Over Bindings @@ -505,12 +419,12 @@ The value of x is: 6 ``` Rust gives the value of `x` as `6`, which is the value from the *second* `let` -statement. There are a few interesting things in this output. First, that Rust +statement. There are a few interesting things in this output. First, Rust will compile and run the program without issue. This is because we haven't mutated the value; instead, we declared a _new_ binding that is _also_ named `x`, and gave it a new value. -The other interesting thing in this output is this error line: +The other interesting thing in this output is this warning line: ```bash src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default @@ -541,12 +455,10 @@ end of a scope. Here’s an example program to illustrate this: ```rust fn main() { let x = 5; - println!("Before shadowing, x is: {}", x); { let x = 6; - println!("Now that x is shadowed, x is: {}", x); } @@ -555,7 +467,7 @@ fn main() { ``` This code first creates the `x` variable and prints `x` to the terminal. Then, -inside a new scope, it creates a new binding for `x` with a new value, and +inside a new scope, it creates a new binding for `x` with a new value and prints that value. When the arbitrary scope ends, `x` is printed once more. If we run this example, we can see the shadow appear and disappear in the output: From ea17980f289ca25cd8d3b21b6f7aec1e06b0c6af Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 3 Jul 2016 18:52:30 -0400 Subject: [PATCH 042/204] Resolve comments in data types --- src/ch03-04-data-types-in-rust.md | 138 ++++++++++-------------------- 1 file changed, 45 insertions(+), 93 deletions(-) diff --git a/src/ch03-04-data-types-in-rust.md b/src/ch03-04-data-types-in-rust.md index f377793403..fe1456254e 100644 --- a/src/ch03-04-data-types-in-rust.md +++ b/src/ch03-04-data-types-in-rust.md @@ -1,21 +1,12 @@ ## Data Types in Rust - Every value in Rust is of a certain *type*, which tells Rust what kind of data -is being given so it knows how to work with that data. You can rely on Rust's ability to -infer types to figure out the type of a binding, or you can annotate it -explicitly if needed. In this section, we'll look at a number of types built -into the language itself split into two subsets of Rust data types: scalar and -compound. First, let's look at how Rust deals with types. - - - +is being given so it knows how to work with that data. You can usually rely on +Rust's ability to infer types to figure out the type of a binding, or you can +annotate it explicitly if needed. In this section, we'll look at a number of +types built into the language itself split into two subsets of Rust data types: +scalar and compound. First, let's look at how Rust deals with types. ### Type Inference and Annotation @@ -26,7 +17,7 @@ declare a type for `x` or `y` in our previous examples. This is because Rust can often tell the type of a binding without you having to declare it. Annotating every single binding with a type can take uneccesary time and make code noisy. To avoid this, Rust uses *type inference*, meaning -that it attempts to infer the types of your bindings by looking at how the +that it attempts to figure out the types of your bindings by looking at how the binding is used. Let’s look at the the first `let` statement you wrote again: ```rust @@ -73,16 +64,11 @@ In the same way as we place the `VALUE` and the `PATTERN` in corresponding positions, we also match up the position of the `TYPE` with the `PATTERN` it corresponds to. - - There are times when multiple types could be correct, and there is not enough -information in the context for Rust to be able to tell which type you want to -use. In those cases type annotations are required. We will look at some of -those situations later, but for now, let's look at the types available in Rust. +information in the surrounding context for Rust to be able to tell which type +you want to use. In those cases type annotations are required. We will look at +some of those situations later, but for now, let's look at the types available +in Rust. ### Scalar Types @@ -107,10 +93,10 @@ built-in integer types in Rust, shown in Table 3-1. | 64-bit | i64 | u64 | | arch | isize | usize | -*Table 3-1: Integer types in Rust. The code (for example, i32) is used to -define a type in a function.* +*Table 3-1: Integer types in Rust. Each code (for example, i32) can be used to +declare the type of a value.* -Each variant can be either signed or unsigned, and has an explicit size. Signed +Each variant can be either signed or unsigned and has an explicit size. Signed and unsigned merely refers to whether it is possible for the number to be either negative or positive, meaning the number needs to have a sign with it ("signed"), or whether it will only ever be positive and can therefore be @@ -136,18 +122,13 @@ collection, which we'll talk about in the "Arrays" section. Rust also has two primitive types for *floating-point numbers*, which are numbers with decimal points. Rust's floating-point types are `f32` and `f64`, which are 32 bits and 64 bits in size, respectively. The default type is `f64`, -as it’s roughly the same speed as `f32`, but has a larger precision. Here's an -example showing floating-point numbers in action: - - - +as it’s roughly the same speed as `f32`, but has a larger precision. It is +possible to use an `f64` on 32 bit systems, but it will be slower than using an +`f32` on those systems. Most of the time, trading potential worse performance +for better precision is a reasonable initial choice, and you should benchmark +your code if you suspect floating-point size is a problem in your case. + +Here's an example showing floating-point numbers in action: ```rust fn main() { @@ -231,12 +212,6 @@ about Unicode Scalar Values at *http://www.unicode.org/glossary/#unicode_scalar_value* and find a chart for all unicode code points at *http://www.unicode.org/charts/*. - - - ### Compound Types *Compound types* can group multiple values of other types into one type. Rust @@ -261,8 +236,8 @@ fn main() { Note that, unlike the examples of multiple bindings, here we bind the single name `tup` to the entire tuple, emphasizing the fact that a tuple is considered -a single compound element. We can then use pattern matching to destructure this -tuple value, like this: +a single compound element. We could then use pattern matching to destructure +this tuple value, like this: ```rust fn main() { @@ -274,12 +249,12 @@ fn main() { } ``` -In this program, we first create a tuple, and bind it to the name `tup`. We -then use a pattern with `let` to take `tup` and turn it into three separate +In this program, we first create a tuple and bind it to the name `tup`. We then +use a pattern with `let` to take `tup` and turn it into three separate bindings, `x`, `y`, and `z`. This is called ‘destructuring’, because it breaks the single tuple into three parts. -Finally, we print the value of `x`, which is `6.4`. +Finally, we print the value of `y`, which is `6.4`. #### Tuple Indexing @@ -303,30 +278,12 @@ This program creates a tuple, `x`, and then makes new bindings to each element by using their index. As with most programming languages, the first index in a tuple is 0. -#### Single-Element Tuples - -Not everything contained within parentheses is a tuple in Rust. For example, a -`(5)` may be a tuple, or just a `5` in parentheses. To disambiguate, use a -comma for single-element tuples, as in this example: - -```rust -fn main() { - let x = (5); - - let x = (5,); -} -``` - -In the first `let` statement, because `(5)` has no comma, it's a simple i32 and -not a tuple. In the second `let` example, `(5,)` is a tuple with only one -element. - ### Arrays -So far, we’ve only represented single values in a binding. Sometimes, though, -it’s useful to bind a name to more than one value. Data structures that contain -multiple values are called *collections*, and arrays are the first type of Rust -collection we’ll learn about. +Another way to bind a name to a collection of multiple values is with an +*array*. Unlike a tuple, every element of an array must have the same type. +Arrays in Rust are different than arrays in some other languages because arrays +in Rust have a fixed length-- once declared, they cannot grow or shrink in size. In Rust, arrays look like this: @@ -337,8 +294,7 @@ fn main() { ``` The values going into an array are written as a comma separated list inside -square brackets. Unlike a tuple, every element of an array must have the same -type. +square brackets. #### Type Annotation for Arrays @@ -375,9 +331,9 @@ running it produces the following output: ```bash $ cargo run Compiling arrays v0.1.0 (file:///projects/arrays) -src/main.rs:4:25: 4:26 error: the trait `core::fmt::Display` is not implemented for the type `[_; 5]` [E0277] -src/main.rs:4 println!(“a is: {}”, a); - ^ +src/main.rs:4:25: 4:26 error: the trait bound `[_; 5]: std::fmt::Display` is not satisfied [E0277] +src/main.rs:4 println!("a is: {}", a); + ^ :2:25: 2:56 note: in this expansion of format_args! :3:1: 3:54 note: in this expansion of print! (defined in ) src/main.rs:4:5: 4:28 note: in this expansion of println! (defined in ) @@ -387,17 +343,17 @@ src/main.rs:4:25: 4:26 note: required by `core::fmt::Display::fmt` error: aborting due to previous error ``` -Whew! The core of the error is this part: *the trait `core::fmt::Display` is -not implemented*. We haven’t discussed traits yet, so this is bound to be -confusing! Here’s all we need to know for now: `println!` can do many kinds of -formatting. By default, `{}` implements a kind of formatting known as -`Display`: output intended for direct end-user consumption. The primitive types -we’ve seen so far implement `Display`, as there’s only one way you’d show a `1` -to a user. But with arrays, the output is less clear. Do you want commas or -not? What about the `[]`s? +Whew! The core of the error is this part: *the trait bound `[_; 5]: +std::fmt::Display` is not satisfied*. We haven’t discussed traits yet, so this +is bound to be confusing! Here’s all we need to know for now: `println!` can do +many kinds of formatting. By default, `{}` implements a kind of formatting +known as `Display`: output intended for direct end-user consumption. The +primitive types we’ve seen so far implement `Display`, as there’s only one way +you’d show a `1` to a user. But with arrays, the output is less clear. Do you +want commas or not? What about the `[]`s? More complex types in the standard library do not automatically implement -`Display` formatting. Instead, Rust implements another kind of formatting, +`Display` formatting. Instead, Rust implements another kind of formatting intended for the programmer. This formatting type is called `Debug`. To ask `println!` to use `Debug` formatting, we include `:?` in the print string, like this: @@ -419,7 +375,7 @@ $ cargo run a is [1, 2, 3, 4, 5] ``` -You’ll see this repeated later, with other types. We’ll cover traits fully in +You’ll see this repeated later with other types. We’ll cover traits fully in Chapter XX. #### Accessing and Modifying Array Elements @@ -456,10 +412,6 @@ fn main() { } ``` - - First, notice the use of `mut` in the array declaration. We had to declare array `a` as `mut` to override Rust's default immutability. The line `a[0] = 7;` modifies the element at index 0 in the array, changing its value to `7`. @@ -486,7 +438,7 @@ fn main() { } ``` -If we use `cargo run` on a project named `arrays` containing this code: +Running this code with `cargo run` produces: ```bash $ cargo run @@ -507,4 +459,4 @@ This is our first example of Rust’s safety principles in action. In many low-level languages, this kind of check is not done, and when you provide an incorrect index, invalid memory can be accessed. Rust protects us against this kind of error by immediately exiting instead of allowing the memory access and -continuing. We'll discuss more of Rust’s error handling in Chapter xx. +continuing. We'll discuss more of Rust’s error handling in Chapter XX. From 5283f0747943ed25db938d64f391d29c71da69e0 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 3 Jul 2016 20:18:01 -0400 Subject: [PATCH 043/204] Resolve comments in functions Fix some parts that didn't make sense anymore since I moved data structures before this section-- tuples and destructuring have already been defined. --- src/ch03-05-how-functions-work-in-rust.md | 245 ++-------------------- 1 file changed, 22 insertions(+), 223 deletions(-) diff --git a/src/ch03-05-how-functions-work-in-rust.md b/src/ch03-05-how-functions-work-in-rust.md index e3f786b158..07a9483df2 100644 --- a/src/ch03-05-how-functions-work-in-rust.md +++ b/src/ch03-05-how-functions-work-in-rust.md @@ -2,13 +2,13 @@ Functions are pervasive in Rust code. We’ve already seen one of the most important functions in the language: the `main()` function that’s the entry -point of every program. We've also seen the `fn` keyword, which allows us to +point of many programs. We've also seen the `fn` keyword, which allows us to declare new functions. Rust code uses *snake case* as the conventional style for function names. In snake case, all letters are lower case, and there are underscores separating words. (Rust also uses snake case for the names of variable bindings; we just -haven't used any variable bindings long enough to need underscores yet.) Here's +haven't used any variable bindings long enough to need underscores yet). Here's a program containing an example function definition: ```rust @@ -23,11 +23,9 @@ fn another_function() { } ``` -Function definitions in Rust always start with `fn` and have a set of parentheses after the function name. The curly -braces tell the compiler where the function body begins and ends. +Function definitions in Rust start with `fn` and have a set of parentheses +after the function name. The curly braces tell the compiler where the function +body begins and ends. We can call any function we’ve defined by entering its name followed by a pair of parentheses. Since `another_function()` is defined in the program, it can be @@ -95,20 +93,8 @@ fn NAME(PATTERN: TYPE) { ``` The parameter declaration in a single-argument function signature looks like -the `let` bindings we used earlier. Just look at both together, and compare -them: - - +the `let` bindings we used earlier in the "Type Inference and Annotation" +section. Just look at both together, and compare them: ```rust,ignore let x: i32; @@ -142,7 +128,7 @@ fn another_function(x: i32, y: i32) { } ``` -In this example, we make a function with two arguments. In this case, both are +In this example, we make a function with two arguments, both of which are `i32`s. If your function has multiple arguments, they don’t need to be the same type, but they just happen to be in this example. Our function then prints out the values of both of its arguments. @@ -181,7 +167,7 @@ fn another_function(x: i32, y: i32) { ``` Instead of passing `5` and `6` directly, this first creates two bindings -containing the values, and passes those bindings instead. When you run this, +containing the values and passes those bindings instead. When you run this, you'll find that it has the same effect as just using integers: ```bash @@ -211,13 +197,6 @@ functions. #### Statements and Expressions - - - We've already been using both statements and expressions. *Statements* are instructions that perform some action and do not return a value. *Expressions* evaluate to a resulting value. Let's look at some examples. @@ -248,34 +227,14 @@ If we were to run this program, we’d get an error like this: ```bash $ cargo run Compiling functions v0.1.0 (file:///projects/functions) -src/main.rs:2:14: 2:17 error: expected identifier, found keyword `let` +src/main.rs:2:14: 2:17 error: expected expression, found statement (`let`) src/main.rs:2 let x = (let y = 6); ^~~ -src/main.rs:2:18: 2:19 error: expected one of `!`, `)`, `,`, `.`, `::`, `{`, or an operator, found `y` -src/main.rs:2 let x = (let y = 6); - ^ -Could not compile `functions`. -``` - - - - The `let y = 6` statement does not return a value, so there isn't anything for `x` to bind to. This is different than in other languages like C and Ruby where the assignment returns the value of the assignment. In those languages, you @@ -327,48 +286,12 @@ semicolons while expressions do not. If you add a semicolon to the end of an expression, that will turn it into a statement, which will then not return a value. Keep this in mind as we explore function return values and expressions. - - ### Functions with Return Values - - - Functions can return values back to the code that calls them. In Rust, the "return value of the function” is synonymous with “the value of the final expression in the block of the body of a function.” A function that returns a value looks like this: - - ```text fn NAME(PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE...) -> TYPE { @@ -420,9 +343,9 @@ let x = 5; ``` The second interesting bit is the `five()` function itself. It requires no -arguments and defines the type of the return, but the body of the function is a -lonely `5` with no semicolon because it is an expression whose value we want to -return. Let's look at another example: +arguments and defines the type of the return value, but the body of the +function is a lonely `5` with no semicolon because it is an expression whose +value we want to return. Let's look at another example: ```rust fn main() { @@ -459,17 +382,16 @@ $ cargo run Compiling functions v0.1.0 (file:///projects/functions) src/main.rs:7:1: 9:2 error: not all control paths return a value [E0269] src/main.rs:7 fn plus_one(x: i32) -> i32 { -src/main.rs:8 x + 1; -src/main.rs:9 } + ^ src/main.rs:7:1: 9:2 help: run `rustc --explain E0269` to see a detailed explanation src/main.rs:8:10: 8:11 help: consider removing this semicolon: src/main.rs:8 x + 1; ^ error: aborting due to previous error -Could not compile `functions`. +error: Could not compile `functions`. ``` -The main error message, "not all control paths return a value," reveals the +The main error message, "not all control paths return a value", reveals the core of the issue with this code. The definition of the function `plus_one` says that it will return an `i32`, but statements don’t evaluate to a value. Therefore, nothing is returned, which contradicts the function definition and @@ -478,20 +400,8 @@ suggests removing the semicolon, which would fix the error. #### Returning Multiple Values -By default, functions can only return single values. There’s a trick, however -to get them to return multiple values. Remember how we used `()`s to create -complex bindings in the "Creating Multiple Bindings" section on page XX? - -```rust -fn main() { - let (x, y) = (5, 6); -} -``` - -Parentheses used in this way form a *tuple*-- a collection of elements that -isn't assigned a name. Tuples are also a basic data type in Rust, and we'll -cover them in detail in the "Tuples" section later in this chapter. For our -purposes now, we can use tuples to return multiple values from functions, as so: +By default, functions can only return single values. There’s a trick, however, +to get them to return multiple values: group them into a tuple! ```rust fn main() { @@ -518,118 +428,7 @@ The value of y is: 6 Let's look at this more closely. First, we're assigning the return value of calling `two_numbers()` to `x` and `y`. In the function signature, we would say -in plain English that the return type `(i32, i32)` translates to “a tuple with +in plain English that the return type `(i32, i32)` translates to "a tuple with two `i32`s in it". These two types are then applied to the tuple to be returned by the function block. In this case, that tuple contains the values `5` and -`6`. This tuple is returned, and assigned to `x` and `y`. - -See how all these bits fit together? We call this behavior of `let` -‘destructuring’, because it takes the structure of the expression that follows -the `=` and takes it apart. - - - - - +`6`. This tuple is returned, and we destructure the tuple and assign the individual values to `x` and `y`. From 690a9724384b0728cc6897314044175b01af0dde Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 5 Jul 2016 10:02:33 -0400 Subject: [PATCH 044/204] Resolve comments in... comments I added a bit about the other style of comments being possible since it's preferred for accessibility reasons: https://github.com/rust-lang/rfcs/pull/1574#discussion_r59236286 --- src/ch03-06-comments.md | 42 ++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/ch03-06-comments.md b/src/ch03-06-comments.md index 2607ad225d..56e2d69870 100644 --- a/src/ch03-06-comments.md +++ b/src/ch03-06-comments.md @@ -1,8 +1,9 @@ ## Comments All programmers strive to make their code easy to understand, but sometimes -some extra explanation is warranted. In these cases, we leave notes in our -source code that the compiler will ignore. These notes are called *comments*. +extra explanation is warranted. In these cases, we leave notes in our source +code that the compiler will ignore but people reading the source code may find +useful. These notes are called *comments*. Here’s a simple comment: @@ -10,9 +11,9 @@ Here’s a simple comment: // Hello, world. ``` -In Rust, comments must start with two slashes, and will last until the end of -the line. For comments that extend beyond a single line, you'll need to include -`//` on each line, like this: +In Rust, comments must start with two slashes and will last until the end of +the line. For comments that extend beyond a single line, you'll either need to +include `//` on each line, like this: ```rust // So we’re doing something complicated here, long enough that we need @@ -20,6 +21,14 @@ the line. For comments that extend beyond a single line, you'll need to include // explain what’s going on. ``` +Or use `/*` at the beginning of your comment and `*/` at the end: + +```rust +/* +Another style of multiline comment! Most Rust code uses the previous +style, but you can use this if you prefer. +*/ +``` Comments can also be placed at the end of lines of code: ```rust @@ -54,7 +63,7 @@ usually people who are using your code, so that they know how to interact with it. Regular comments won't be shown in `rustdoc` generated HTML, so their intended audience is people who are reading and editing your code. -Documentation comments use an extra slash, like this: +Documentation comments use an extra slash or an extra star, like this: ```rust /// The foo function doesn’t really do much. @@ -67,12 +76,21 @@ fn foo() { /// like we did before. fn bar() { +} + +/** +Multiple line documentation comments +can also use this style. +*/ +fn baz() { + } ``` -The `rustdoc` tool would interpret each comment in this example as documenting +The `rustdoc` tool will interpret each comment in this example as documenting the thing that follows it. The first comment would be used to document the -`foo()` function, and the second comment would document the `bar()` function. +`foo()` function, the second comment would document the `bar()` function, and +so forth. Because documentation comments have semantic meaning to `rustdoc`, the compiler will pay attention to the placement of your documentation comments. For @@ -94,8 +112,6 @@ This happens because Rust expects a document comment to be associated with whatever code comes directly after it, so it sees that a document comment alone must be a mistake. - +Providing documentation for libraries is a best practice that the Rust community +strives to do to be helpful to each other. We'll cover how you can generate +great API documentation for your library in more detail in Chapter XX. From 8c6919d67a75e3b25ca2d9ff5ef992952a3a3805 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 5 Jul 2016 10:52:00 -0400 Subject: [PATCH 045/204] Address comments in control flow --- src/ch03-07-control-flow.md | 140 ++++++++++++++---------------------- 1 file changed, 53 insertions(+), 87 deletions(-) diff --git a/src/ch03-07-control-flow.md b/src/ch03-07-control-flow.md index c5d330ca34..e106549ed6 100644 --- a/src/ch03-07-control-flow.md +++ b/src/ch03-07-control-flow.md @@ -1,9 +1,12 @@ ## Control Flow - +Deciding whether or not to run some code depending on if a condition is true, +or deciding to run some code repeatedly while a condition is true, are basic +building blocks in most programming languages. The most common constructs that +let us control the flow of execution of our Rust code are `if` expressions and +loops. -### `if` Statements +### `if` Expressions > Two roads diverged in a yellow wood, > And sorry I could not travel both @@ -13,10 +16,9 @@ if and loops sections here? /Liz --> > > - Robert Frost, “The Road Not Taken” -In Rust, as in most programming languages, an `if` expression allows us to -branch our code depending on conditions. We provide a condition, and then say, -`if` this condition is met, then run this block of code. If the condition is -not met, do not run this block of code. +An `if` expression allows us to branch our code depending on conditions. We +provide a condition and then say, "If this condition is met, then run this +block of code. If the condition is not met, do not run this block of code." Let’s make a new project to explore `if`. Navigate to your projects directory, and use Cargo to make a new project called `branches`: @@ -40,7 +42,7 @@ fn main() { ``` The `condition` variable is a boolean; here, it's set to true. All `if` -statements start with `if`, which is followed by a condition. The block of code +expressions start with `if`, which is followed by a condition. The block of code we want to execute if the condition is true goes immediately after the condition, inside curly braces. These blocks are sometimes called ‘arms’. @@ -98,17 +100,6 @@ condition was false This time, because `condition` was false and we have an `else` block, the `else` block was executed. - - - It’s also worth noting that `condition` here _must_ be a `bool`. To see what happens if the condition isn't a `bool`, try running this code: @@ -142,10 +133,19 @@ Could not compile `branches`. The error tells us that Rust expected a `bool`, but got an integer. Rust will not automatically try to convert non-boolean types to a boolean here, unlike languages like Ruby or JavaScript. We must be explicit and always give `if` a -`boolean` as its condition. +`boolean` as its condition. If your intention is for the `if` code block to be run if a number is not equal to `0`, for example, we would change the `if` expression to read: + +```rust +fn main() { + let condition = 5; + + if condition != 0 { + println!("condition was something other than zero"); + } +} +``` - - +Running this will print "condition was something other than zero". #### Multiple Conditions with `else if` @@ -218,9 +218,9 @@ The value of number is: 5 Remember, blocks of code evaluate to the last expression in them, and numbers by themselves are also expressions. In this case, the value of the whole `if` expression depends on which block of code executes. This means that the value -in both arms of the `if` must be the same type; in the previous example, they -were both `i32` integers. But what happens if the types are mismatched, as in -the following example? +that results from both arms of the `if` must be the same type; in the previous +example, they were both `i32` integers. But what happens if the types are +mismatched, as in the following example? ```rust,ignore fn main() { @@ -236,9 +236,9 @@ fn main() { } ``` -The expression in one block of the `if` statement, is an integer and the -expresion in the other block is a string. If we try to run this, we’ll get an -error: +The expression in the `if` block is an integer and the expresion in the `else` +block is a string. This can’t work, because variable bindings must have a +single type. If we try to run this, we’ll get an error: ```bash Compiling branches v0.1.0 (file:///projects/branches) @@ -258,8 +258,7 @@ Could not compile `branches`. ``` The `if` and `else` arms have value types that are incompatible, and Rust tells -us exactly where to find the problem in our program. This can’t work, because -variable bindings must have a single type. +us exactly where to find the problem in our program. ### Repetition with Loops @@ -279,12 +278,8 @@ in. #### Repeating Code with `loop` - - - The `loop` keyword tells Rust to execute a block of code over and over again -forever, or until we explicitly tell it to stop. +forever or until we explicitly tell it to stop. For an example, change the *src/main.rs* file in your *loops* directory to look like this: @@ -311,15 +306,12 @@ again! again! ^Cagain! ``` - - -That `^C` there is where I hit `control-c`. Fortunately, Rust provides another, -more reliable way to break out of a loop. We can place the `break` keyword -within the loop to tell the program when to stop executing the loop. Try this -version of the program out: +That `^C` there is where I hit `control-c`. You may or may not see "again!" printed after the `^C`, depending on where the code was in the loop when it received the signal to halt. + +Fortunately, Rust provides another, more reliable way to break out of a loop. +We can place the `break` keyword within the loop to tell the program when to +stop executing the loop. Try this version of the program out: ```rust fn main() { @@ -384,24 +376,10 @@ This program loops three times, counting down each time. Finally, after the loop, it prints another message, then exits. The core of this example is in the combination of `loop`, `if`, `else`, and -`break`. - - - - - -We want to `loop`, but only while some sort of condition is true. As soon as it -isn't, we want to `break` out of the loop. This pattern is so common that Rust -has a more efficient language construct for it, called a `while` loop. Here's -the same example, but using `while` instead: +`break`. We want to `loop`, but only while some sort of condition is true. As +soon as it isn't, we want to `break` out of the loop. This pattern is so common +that Rust has a more efficient language construct for it, called a `while` +loop. Here's the same example, but using `while` instead: ```rust fn main() { @@ -438,10 +416,6 @@ fn main() { } ``` - - Here, we're counting up through the elements in the array. We start at index 0, then loop until we hit the final index of our array (that is, when `index < 5` is no longer true). Running this will print out every element of the array: @@ -466,8 +440,8 @@ getting the index length incorrect. It's also slow, as the compiler needs to perform the conditional check on every element on every iteration through the loop. -As a more efficient alternative, we can use a `for` loop. A `for` loop looks -something like this: +As a more efficient alternative, we can use a `for` loop and execute some code +for each item in a collection. A `for` loop looks like this: ```rust fn main() { @@ -479,25 +453,17 @@ fn main() { } ``` -** NOTE: see [https://github.com/rust-lang/rust/issues/25725#issuecomment-166365658](https://github.com/rust-lang/rust/issues/25725#issuecomment-166365658), we may want to change this ** - - -If we run this, we'll see the same output as the previous example. - - - - - -** I'm going to leave it at this for now until we decide how we want to do it** +If we run this, we'll see the same output as the previous example. Importantly, +though, we've now increased the safety of our code and eliminated the chance of +bugs resulting from going beyond the end of the array or not going far enough +and missing some items. - +For example, in the previous code that uses the `while` loop, if we removed an +item from the `a` array but forgot to update the condition to be `while index < +4`, our code would panic. Using the `for` loop means we would not need to +remember to change any other code if we changed the the number of values in the +array. - +If you're wondering about the `.iter()` code in this example, keep reading! We +will cover method syntax generally in Chapter XX and iterators specifically in +Chapter XX. For now, though, let's get into the concept of ownership. From 63523d45b56d3540bb896d97de257c0c0e19a08b Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 5 Jul 2016 15:12:33 -0400 Subject: [PATCH 046/204] Remove unneeded indent --- src/ch03-02-anatomy-of-a-rust-program.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch03-02-anatomy-of-a-rust-program.md b/src/ch03-02-anatomy-of-a-rust-program.md index a1d270d5e4..f935694aac 100644 --- a/src/ch03-02-anatomy-of-a-rust-program.md +++ b/src/ch03-02-anatomy-of-a-rust-program.md @@ -135,7 +135,7 @@ the function’s body. Inside the function body, we added the following: ```rust,ignore - let x = 5; +let x = 5; ``` This is a `let` statement, and it binds the value `5` to the variable `x`. From 1f5b8c74caa19275cc37b9d1ad6ce66005314f3f Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 5 Jul 2016 15:12:56 -0400 Subject: [PATCH 047/204] Remove extra newline --- src/ch03-04-data-types-in-rust.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ch03-04-data-types-in-rust.md b/src/ch03-04-data-types-in-rust.md index fe1456254e..7c856cf37a 100644 --- a/src/ch03-04-data-types-in-rust.md +++ b/src/ch03-04-data-types-in-rust.md @@ -1,4 +1,3 @@ - ## Data Types in Rust Every value in Rust is of a certain *type*, which tells Rust what kind of data From 48d3255920cf19ad3617a4f1ce20a97672496eb0 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 5 Jul 2016 15:13:29 -0400 Subject: [PATCH 048/204] Fix alignment of the first line in the table --- src/ch03-04-data-types-in-rust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch03-04-data-types-in-rust.md b/src/ch03-04-data-types-in-rust.md index 7c856cf37a..62838f5c9c 100644 --- a/src/ch03-04-data-types-in-rust.md +++ b/src/ch03-04-data-types-in-rust.md @@ -86,7 +86,7 @@ built-in integer types in Rust, shown in Table 3-1. | Length | signed | unsigned | |--------|--------|----------| -| 8-bit | i8 | u8 | +| 8-bit | i8 | u8 | | 16-bit | i16 | u16 | | 32-bit | i32 | u32 | | 64-bit | i64 | u64 | From 4efe6824d81f72d726f543ddbe551e15795d639b Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 5 Jul 2016 15:28:41 -0400 Subject: [PATCH 049/204] Put back the trailing whitespace to get newlines Bad text editor. Not helpful. No. --- src/ch03-07-control-flow.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ch03-07-control-flow.md b/src/ch03-07-control-flow.md index e106549ed6..3e9941d80c 100644 --- a/src/ch03-07-control-flow.md +++ b/src/ch03-07-control-flow.md @@ -8,12 +8,12 @@ loops. ### `if` Expressions -> Two roads diverged in a yellow wood, -> And sorry I could not travel both -> And be one traveler, long I stood -> And looked down one as far as I could -> To where it bent in the undergrowth; -> +> Two roads diverged in a yellow wood, +> And sorry I could not travel both +> And be one traveler, long I stood +> And looked down one as far as I could +> To where it bent in the undergrowth; +> > - Robert Frost, “The Road Not Taken” An `if` expression allows us to branch our code depending on conditions. We From cda62ba0eff126ce92b86c2940c963bb49735ddf Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 5 Jul 2016 19:17:00 -0400 Subject: [PATCH 050/204] First rule about block comments: don't talk about block comments --- src/ch03-06-comments.md | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/src/ch03-06-comments.md b/src/ch03-06-comments.md index 56e2d69870..391edb3ec8 100644 --- a/src/ch03-06-comments.md +++ b/src/ch03-06-comments.md @@ -12,7 +12,7 @@ Here’s a simple comment: ``` In Rust, comments must start with two slashes and will last until the end of -the line. For comments that extend beyond a single line, you'll either need to +the line. For comments that extend beyond a single line, you'll need to include `//` on each line, like this: ```rust @@ -21,14 +21,6 @@ include `//` on each line, like this: // explain what’s going on. ``` -Or use `/*` at the beginning of your comment and `*/` at the end: - -```rust -/* -Another style of multiline comment! Most Rust code uses the previous -style, but you can use this if you prefer. -*/ -``` Comments can also be placed at the end of lines of code: ```rust @@ -63,7 +55,7 @@ usually people who are using your code, so that they know how to interact with it. Regular comments won't be shown in `rustdoc` generated HTML, so their intended audience is people who are reading and editing your code. -Documentation comments use an extra slash or an extra star, like this: +Documentation comments use an extra slash, like this: ```rust /// The foo function doesn’t really do much. @@ -76,21 +68,12 @@ fn foo() { /// like we did before. fn bar() { -} - -/** -Multiple line documentation comments -can also use this style. -*/ -fn baz() { - } ``` The `rustdoc` tool will interpret each comment in this example as documenting the thing that follows it. The first comment would be used to document the -`foo()` function, the second comment would document the `bar()` function, and -so forth. +`foo()` function and the second comment would document the `bar()` function. Because documentation comments have semantic meaning to `rustdoc`, the compiler will pay attention to the placement of your documentation comments. For From 4801fe6aa503ec5e4e5d2589dcce2655db02e0b2 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 8 Jul 2016 10:41:21 -0400 Subject: [PATCH 051/204] Pull the guessing game tutorial over from the existing book --- src/SUMMARY.md | 2 +- src/ch02-01-guessing-game-tutorial.md | 994 ++++++++++++++++++++++++++ 2 files changed, 995 insertions(+), 1 deletion(-) create mode 100644 src/ch02-01-guessing-game-tutorial.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index e5d428b065..e26a8eebd4 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -5,7 +5,7 @@ - [Hello, World!](ch01-03-hello-world.md) - [The Design of Rust](ch01-04-design.md) -- [Tutorial]() +- [Guessing Game Tutorial](ch02-01-guessing-game-tutorial.md) - [Up and Running](ch03-01-up-and-running.md) - [Variable Bindings](ch03-02-variable-bindings.md) diff --git a/src/ch02-01-guessing-game-tutorial.md b/src/ch02-01-guessing-game-tutorial.md new file mode 100644 index 0000000000..6ec0fe3922 --- /dev/null +++ b/src/ch02-01-guessing-game-tutorial.md @@ -0,0 +1,994 @@ +# Guessing Game + +Let’s learn some Rust! For our first project, we’ll implement a classic +beginner programming problem: the guessing game. Here’s how it works: Our +program will generate a random integer between one and a hundred. It will then +prompt us to enter a guess. Upon entering our guess, it will tell us if we’re +too low or too high. Once we guess correctly, it will congratulate us. Sounds +good? + +Along the way, we’ll learn a little bit about Rust. The next chapter, ‘Syntax +and Semantics’, will dive deeper into each part. + +## Set up + +Let’s set up a new project. Go to your projects directory. Remember how we had +to create our directory structure and a `Cargo.toml` for `hello_world`? Cargo +has a command that does that for us. Let’s give it a shot: + +```bash +$ cd ~/projects +$ cargo new guessing_game --bin +$ cd guessing_game +``` + +We pass the name of our project to `cargo new`, and then the `--bin` flag, +since we’re making a binary, rather than a library. + +Check out the generated `Cargo.toml`: + +```toml +[package] + +name = "guessing_game" +version = "0.1.0" +authors = ["Your Name "] +``` + +Cargo gets this information from your environment. If it’s not correct, go ahead +and fix that. + +Finally, Cargo generated a ‘Hello, world!’ for us. Check out `src/main.rs`: + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +Let’s try compiling what Cargo gave us: + +```{bash} +$ cargo build + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) +``` + +Excellent! Open up your `src/main.rs` again. We’ll be writing all of +our code in this file. + +Before we move on, let me show you one more Cargo command: `run`. `cargo run` +is kind of like `cargo build`, but it also then runs the produced executable. +Try it out: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/debug/guessing_game` +Hello, world! +``` + +Great! The `run` command comes in handy when you need to rapidly iterate on a +project. Our game is such a project, we need to quickly test each +iteration before moving on to the next one. + +## Processing a Guess + +Let’s get to it! The first thing we need to do for our guessing game is +allow our player to input a guess. Put this in your `src/main.rs`: + +```rust,no_run +use std::io; + +fn main() { + println!("Guess the number!"); + + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("Failed to read line"); + + println!("You guessed: {}", guess); +} +``` + +There’s a lot here! Let’s go over it, bit by bit. + +```rust,ignore +use std::io; +``` + +We’ll need to take user input, and then print the result as output. As such, we +need the `io` library from the standard library. Rust only imports a few things +by default into every program, [the ‘prelude’][prelude]. If it’s not in the +prelude, you’ll have to `use` it directly. There is also a second ‘prelude’, the +[`io` prelude][ioprelude], which serves a similar function: you import it, and it +imports a number of useful, `io`-related things. + +[prelude]: ../std/prelude/index.html +[ioprelude]: ../std/io/prelude/index.html + +```rust,ignore +fn main() { +``` + +As you’ve seen before, the `main()` function is the entry point into your +program. The `fn` syntax declares a new function, the `()`s indicate that +there are no arguments, and `{` starts the body of the function. Because +we didn’t include a return type, it’s assumed to be `()`, an empty +[tuple][tuples]. + +[tuples]: primitive-types.html#tuples + +```rust,ignore + println!("Guess the number!"); + + println!("Please input your guess."); +``` + +We previously learned that `println!()` is a [macro][macros] that +prints a [string][strings] to the screen. + +[macros]: macros.html +[strings]: strings.html + +```rust,ignore + let mut guess = String::new(); +``` + +Now we’re getting interesting! There’s a lot going on in this little line. +The first thing to notice is that this is a [let statement][let], which is +used to create ‘variable bindings’. They take this form: + +```rust,ignore +let foo = bar; +``` + +[let]: variable-bindings.html + +This will create a new binding named `foo`, and bind it to the value `bar`. In +many languages, this is called a ‘variable’, but Rust’s variable bindings have +a few tricks up their sleeves. + +For example, they’re [immutable][immutable] by default. That’s why our example +uses `mut`: it makes a binding mutable, rather than immutable. `let` doesn’t +take a name on the left hand side of the assignment, it actually accepts a +‘[pattern][patterns]’. We’ll use patterns later. It’s easy enough +to use for now: + +```rust +let foo = 5; // immutable. +let mut bar = 5; // mutable +``` + +[immutable]: mutability.html +[patterns]: patterns.html + +Oh, and `//` will start a comment, until the end of the line. Rust ignores +everything in [comments][comments]. + +[comments]: comments.html + +So now we know that `let mut guess` will introduce a mutable binding named +`guess`, but we have to look at the other side of the `=` for what it’s +bound to: `String::new()`. + +`String` is a string type, provided by the standard library. A +[`String`][string] is a growable, UTF-8 encoded bit of text. + +[string]: ../std/string/struct.String.html + +The `::new()` syntax uses `::` because this is an ‘associated function’ of +a particular type. That is to say, it’s associated with `String` itself, +rather than a particular instance of a `String`. Some languages call this a +‘static method’. + +This function is named `new()`, because it creates a new, empty `String`. +You’ll find a `new()` function on many types, as it’s a common name for making +a new value of some kind. + +Let’s move forward: + +```rust,ignore + io::stdin().read_line(&mut guess) + .expect("Failed to read line"); +``` + +That’s a lot more! Let’s go bit-by-bit. The first line has two parts. Here’s +the first: + +```rust,ignore +io::stdin() +``` + +Remember how we `use`d `std::io` on the first line of the program? We’re now +calling an associated function on it. If we didn’t `use std::io`, we could +have written this line as `std::io::stdin()`. + +This particular function returns a handle to the standard input for your +terminal. More specifically, a [std::io::Stdin][iostdin]. + +[iostdin]: ../std/io/struct.Stdin.html + +The next part will use this handle to get input from the user: + +```rust,ignore +.read_line(&mut guess) +``` + +Here, we call the [`read_line()`][read_line] method on our handle. +[Methods][method] are like associated functions, but are only available on a +particular instance of a type, rather than the type itself. We’re also passing +one argument to `read_line()`: `&mut guess`. + +[read_line]: ../std/io/struct.Stdin.html#method.read_line +[method]: method-syntax.html + +Remember how we bound `guess` above? We said it was mutable. However, +`read_line` doesn’t take a `String` as an argument: it takes a `&mut String`. +Rust has a feature called ‘[references][references]’, which allows you to have +multiple references to one piece of data, which can reduce copying. References +are a complex feature, as one of Rust’s major selling points is how safe and +easy it is to use references. We don’t need to know a lot of those details to +finish our program right now, though. For now, all we need to know is that +like `let` bindings, references are immutable by default. Hence, we need to +write `&mut guess`, rather than `&guess`. + +Why does `read_line()` take a mutable reference to a string? Its job is +to take what the user types into standard input, and place that into a +string. So it takes that string as an argument, and in order to add +the input, it needs to be mutable. + +[references]: references-and-borrowing.html + +But we’re not quite done with this line of code, though. While it’s +a single line of text, it’s only the first part of the single logical line of +code: + +```rust,ignore + .expect("Failed to read line"); +``` + +When you call a method with the `.foo()` syntax, you may introduce a newline +and other whitespace. This helps you split up long lines. We _could_ have +done: + +```rust,ignore + io::stdin().read_line(&mut guess).expect("failed to read line"); +``` + +But that gets hard to read. So we’ve split it up, two lines for two method +calls. We already talked about `read_line()`, but what about `expect()`? Well, +we already mentioned that `read_line()` puts what the user types into the `&mut +String` we pass it. But it also returns a value: in this case, an +[`io::Result`][ioresult]. Rust has a number of types named `Result` in its +standard library: a generic [`Result`][result], and then specific versions for +sub-libraries, like `io::Result`. + +[ioresult]: ../std/io/type.Result.html +[result]: ../std/result/enum.Result.html + +The purpose of these `Result` types is to encode error handling information. +Values of the `Result` type, like any type, have methods defined on them. In +this case, `io::Result` has an [`expect()` method][expect] that takes a value +it’s called on, and if it isn’t a successful one, [`panic!`][panic]s with a +message you passed it. A `panic!` like this will cause our program to crash, +displaying the message. + +[expect]: ../std/result/enum.Result.html#method.expect +[panic]: error-handling.html + +If we leave off calling this method, our program will compile, but +we’ll get a warning: + +```bash +$ cargo build + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) +src/main.rs:10:5: 10:39 warning: unused result which must be used, +#[warn(unused_must_use)] on by default +src/main.rs:10 io::stdin().read_line(&mut guess); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +Rust warns us that we haven’t used the `Result` value. This warning comes from +a special annotation that `io::Result` has. Rust is trying to tell you that +you haven’t handled a possible error. The right way to suppress the error is +to actually write error handling. Luckily, if we want to crash if there’s +a problem, we can use `expect()`. If we can recover from the +error somehow, we’d do something else, but we’ll save that for a future +project. + +There’s only one line of this first example left: + +```rust,ignore + println!("You guessed: {}", guess); +} +``` + +This prints out the string we saved our input in. The `{}`s are a placeholder, +and so we pass it `guess` as an argument. If we had multiple `{}`s, we would +pass multiple arguments: + +```rust +let x = 5; +let y = 10; + +println!("x and y: {} and {}", x, y); +``` + +Easy. + +Anyway, that’s the tour. We can run what we have with `cargo run`: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/debug/guessing_game` +Guess the number! +Please input your guess. +6 +You guessed: 6 +``` + +All right! Our first part is done: we can get input from the keyboard, +and then print it back out. + +# Generating a secret number + +Next, we need to generate a secret number. Rust does not yet include random +number functionality in its standard library. The Rust team does, however, +provide a [`rand` crate][randcrate]. A ‘crate’ is a package of Rust code. +We’ve been building a ‘binary crate’, which is an executable. `rand` is a +‘library crate’, which contains code that’s intended to be used with other +programs. + +[randcrate]: https://crates.io/crates/rand + +Using external crates is where Cargo really shines. Before we can write +the code using `rand`, we need to modify our `Cargo.toml`. Open it up, and +add these few lines at the bottom: + +```toml +[dependencies] + +rand="0.3.0" +``` + +The `[dependencies]` section of `Cargo.toml` is like the `[package]` section: +everything that follows it is part of it, until the next section starts. +Cargo uses the dependencies section to know what dependencies on external +crates you have, and what versions you require. In this case, we’ve specified version `0.3.0`, +which Cargo understands to be any release that’s compatible with this specific version. +Cargo understands [Semantic Versioning][semver], which is a standard for writing version +numbers. A bare number like above is actually shorthand for `^0.3.0`, +meaning "anything compatible with 0.3.0". +If we wanted to use only `0.3.0` exactly, we could say `rand="=0.3.0"` +(note the two equal signs). +And if we wanted to use the latest version we could use `*`. +We could also use a range of versions. +[Cargo’s documentation][cargodoc] contains more details. + +[semver]: http://semver.org +[cargodoc]: http://doc.crates.io/crates-io.html + +Now, without changing any of our code, let’s build our project: + +```bash +$ cargo build + Updating registry `https://github.com/rust-lang/crates.io-index` + Downloading rand v0.3.8 + Downloading libc v0.1.6 + Compiling libc v0.1.6 + Compiling rand v0.3.8 + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) +``` + +(You may see different versions, of course.) + +Lots of new output! Now that we have an external dependency, Cargo fetches the +latest versions of everything from the registry, which is a copy of data from +[Crates.io][cratesio]. Crates.io is where people in the Rust ecosystem +post their open source Rust projects for others to use. + +[cratesio]: https://crates.io + +After updating the registry, Cargo checks our `[dependencies]` and downloads +any we don’t have yet. In this case, while we only said we wanted to depend on +`rand`, we’ve also grabbed a copy of `libc`. This is because `rand` depends on +`libc` to work. After downloading them, it compiles them, and then compiles +our project. + +If we run `cargo build` again, we’ll get different output: + +```bash +$ cargo build +``` + +That’s right, no output! Cargo knows that our project has been built, and that +all of its dependencies are built, and so there’s no reason to do all that +stuff. With nothing to do, it simply exits. If we open up `src/main.rs` again, +make a trivial change, and then save it again, we’ll only see one line: + +```bash +$ cargo build + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) +``` + +So, we told Cargo we wanted any `0.3.x` version of `rand`, and so it fetched the latest +version at the time this was written, `v0.3.8`. But what happens when next +week, version `v0.3.9` comes out, with an important bugfix? While getting +bugfixes is important, what if `0.3.9` contains a regression that breaks our +code? + +The answer to this problem is the `Cargo.lock` file you’ll now find in your +project directory. When you build your project for the first time, Cargo +figures out all of the versions that fit your criteria, and then writes them +to the `Cargo.lock` file. When you build your project in the future, Cargo +will see that the `Cargo.lock` file exists, and then use that specific version +rather than do all the work of figuring out versions again. This lets you +have a repeatable build automatically. In other words, we’ll stay at `0.3.8` +until we explicitly upgrade, and so will anyone who we share our code with, +thanks to the lock file. + +What about when we _do_ want to use `v0.3.9`? Cargo has another command, +`update`, which says ‘ignore the lock, figure out all the latest versions that +fit what we’ve specified. If that works, write those versions out to the lock +file’. But, by default, Cargo will only look for versions larger than `0.3.0` +and smaller than `0.4.0`. If we want to move to `0.4.x`, we’d have to update +the `Cargo.toml` directly. When we do, the next time we `cargo build`, Cargo +will update the index and re-evaluate our `rand` requirements. + +There’s a lot more to say about [Cargo][doccargo] and [its +ecosystem][doccratesio], but for now, that’s all we need to know. Cargo makes +it really easy to re-use libraries, and so Rustaceans tend to write smaller +projects which are assembled out of a number of sub-packages. + +[doccargo]: http://doc.crates.io +[doccratesio]: http://doc.crates.io/crates-io.html + +Let’s get on to actually _using_ `rand`. Here’s our next step: + +```rust,ignore +extern crate rand; + +use std::io; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + println!("You guessed: {}", guess); +} +``` + +The first thing we’ve done is change the first line. It now says +`extern crate rand`. Because we declared `rand` in our `[dependencies]`, we +can use `extern crate` to let Rust know we’ll be making use of it. This also +does the equivalent of a `use rand;` as well, so we can make use of anything +in the `rand` crate by prefixing it with `rand::`. + +Next, we added another `use` line: `use rand::Rng`. We’re going to use a +method in a moment, and it requires that `Rng` be in scope to work. The basic +idea is this: methods are defined on something called ‘traits’, and for the +method to work, it needs the trait to be in scope. For more about the +details, read the [traits][traits] section. + +[traits]: traits.html + +There are two other lines we added, in the middle: + +```rust,ignore + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); +``` + +We use the `rand::thread_rng()` function to get a copy of the random number +generator, which is local to the particular [thread][concurrency] of execution +we’re in. Because we `use rand::Rng`’d above, it has a `gen_range()` method +available. This method takes two arguments, and generates a number between +them. It’s inclusive on the lower bound, but exclusive on the upper bound, +so we need `1` and `101` to get a number ranging from one to a hundred. + +[concurrency]: concurrency.html + +The second line prints out the secret number. This is useful while +we’re developing our program, so we can easily test it out. But we’ll be +deleting it for the final version. It’s not much of a game if it prints out +the answer when you start it up! + +Try running our new program a few times: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/debug/guessing_game` +Guess the number! +The secret number is: 7 +Please input your guess. +4 +You guessed: 4 +$ cargo run + Running `target/debug/guessing_game` +Guess the number! +The secret number is: 83 +Please input your guess. +5 +You guessed: 5 +``` + +Great! Next up: comparing our guess to the secret number. + +# Comparing guesses + +Now that we’ve got user input, let’s compare our guess to the secret number. +Here’s our next step, though it doesn’t quite compile yet: + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), + } +} +``` + +A few new bits here. The first is another `use`. We bring a type called +`std::cmp::Ordering` into scope. Then, five new lines at the bottom that use +it: + +```rust,ignore +match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), +} +``` + +The `cmp()` method can be called on anything that can be compared, and it +takes a reference to the thing you want to compare it to. It returns the +`Ordering` type we `use`d earlier. We use a [`match`][match] statement to +determine exactly what kind of `Ordering` it is. `Ordering` is an +[`enum`][enum], short for ‘enumeration’, which looks like this: + +```rust +enum Foo { + Bar, + Baz, +} +``` + +[match]: match.html +[enum]: enums.html + +With this definition, anything of type `Foo` can be either a +`Foo::Bar` or a `Foo::Baz`. We use the `::` to indicate the +namespace for a particular `enum` variant. + +The [`Ordering`][ordering] `enum` has three possible variants: `Less`, `Equal`, +and `Greater`. The `match` statement takes a value of a type, and lets you +create an ‘arm’ for each possible value. Since we have three types of +`Ordering`, we have three arms: + +```rust,ignore +match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), +} +``` + +[ordering]: ../std/cmp/enum.Ordering.html + +If it’s `Less`, we print `Too small!`, if it’s `Greater`, `Too big!`, and if +`Equal`, `You win!`. `match` is really useful, and is used often in Rust. + +I did mention that this won’t quite compile yet, though. Let’s try it: + +```bash +$ cargo build + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) +src/main.rs:28:21: 28:35 error: mismatched types: + expected `&collections::string::String`, + found `&_` +(expected struct `collections::string::String`, + found integral variable) [E0308] +src/main.rs:28 match guess.cmp(&secret_number) { + ^~~~~~~~~~~~~~ +error: aborting due to previous error +Could not compile `guessing_game`. +``` + +Whew! This is a big error. The core of it is that we have ‘mismatched types’. +Rust has a strong, static type system. However, it also has type inference. +When we wrote `let guess = String::new()`, Rust was able to infer that `guess` +should be a `String`, and so it doesn’t make us write out the type. And with +our `secret_number`, there are a number of types which can have a value +between one and a hundred: `i32`, a thirty-two-bit number, or `u32`, an +unsigned thirty-two-bit number, or `i64`, a sixty-four-bit number or others. +So far, that hasn’t mattered, and so Rust defaults to an `i32`. However, here, +Rust doesn’t know how to compare the `guess` and the `secret_number`. They +need to be the same type. Ultimately, we want to convert the `String` we +read as input into a real number type, for comparison. We can do that +with two more lines. Here’s our new program: + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), + } +} +``` + +The new two lines: + +```rust,ignore + let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); +``` + +Wait a minute, I thought we already had a `guess`? We do, but Rust allows us +to ‘shadow’ the previous `guess` with a new one. This is often used in this +exact situation, where `guess` starts as a `String`, but we want to convert it +to an `u32`. Shadowing lets us re-use the `guess` name, rather than forcing us +to come up with two unique names like `guess_str` and `guess`, or something +else. + +We bind `guess` to an expression that looks like something we wrote earlier: + +```rust,ignore +guess.trim().parse() +``` + +Here, `guess` refers to the old `guess`, the one that was a `String` with our +input in it. The `trim()` method on `String`s will eliminate any white space at +the beginning and end of our string. This is important, as we had to press the +‘return’ key to satisfy `read_line()`. This means that if we type `5` and hit +return, `guess` looks like this: `5\n`. The `\n` represents ‘newline’, the +enter key. `trim()` gets rid of this, leaving our string with only the `5`. The +[`parse()` method on strings][parse] parses a string into some kind of number. +Since it can parse a variety of numbers, we need to give Rust a hint as to the +exact type of number we want. Hence, `let guess: u32`. The colon (`:`) after +`guess` tells Rust we’re going to annotate its type. `u32` is an unsigned, +thirty-two bit integer. Rust has [a number of built-in number types][number], +but we’ve chosen `u32`. It’s a good default choice for a small positive number. + +[parse]: ../std/primitive.str.html#method.parse +[number]: primitive-types.html#numeric-types + +Just like `read_line()`, our call to `parse()` could cause an error. What if +our string contained `A👍%`? There’d be no way to convert that to a number. As +such, we’ll do the same thing we did with `read_line()`: use the `expect()` +method to crash if there’s an error. + +Let’s try our program out! + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/guessing_game` +Guess the number! +The secret number is: 58 +Please input your guess. + 76 +You guessed: 76 +Too big! +``` + +Nice! You can see I even added spaces before my guess, and it still figured +out that I guessed 76. Run the program a few times, and verify that guessing +the number works, as well as guessing a number too small. + +Now we’ve got most of the game working, but we can only make one guess. Let’s +change that by adding loops! + +# Looping + +The `loop` keyword gives us an infinite loop. Let’s add that in: + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + loop { + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), + } + } +} +``` + +And try it out. But wait, didn’t we just add an infinite loop? Yup. Remember +our discussion about `parse()`? If we give a non-number answer, we’ll `panic!` +and quit. Observe: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/guessing_game` +Guess the number! +The secret number is: 59 +Please input your guess. +45 +You guessed: 45 +Too small! +Please input your guess. +60 +You guessed: 60 +Too big! +Please input your guess. +59 +You guessed: 59 +You win! +Please input your guess. +quit +thread 'main' panicked at 'Please type a number!' +``` + +Ha! `quit` actually quits. As does any other non-number input. Well, this is +suboptimal to say the least. First, let’s actually quit when you win the game: + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + loop { + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => { + println!("You win!"); + break; + } + } + } +} +``` + +By adding the `break` line after the `You win!`, we’ll exit the loop when we +win. Exiting the loop also means exiting the program, since it’s the last +thing in `main()`. We have only one more tweak to make: when someone inputs a +non-number, we don’t want to quit, we want to ignore it. We can do that +like this: + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + loop { + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + let guess: u32 = match guess.trim().parse() { + Ok(num) => num, + Err(_) => continue, + }; + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => { + println!("You win!"); + break; + } + } + } +} +``` + +These are the lines that changed: + +```rust,ignore +let guess: u32 = match guess.trim().parse() { + Ok(num) => num, + Err(_) => continue, +}; +``` +This is how you generally move from ‘crash on error’ to ‘actually handle the +error’, by switching from `expect()` to a `match` statement. A `Result` is +returned by `parse()`, this is an `enum` like `Ordering`, but in this case, +each variant has some data associated with it: `Ok` is a success, and `Err` is a +failure. Each contains more information: the successfully parsed integer, or an +error type. In this case, we `match` on `Ok(num)`, which sets the name `num` to +the unwrapped `Ok` value (the integer), and then we return it on the +right-hand side. In the `Err` case, we don’t care what kind of error it is, so +we just use the catch all `_` instead of a name. This catches everything that +isn't `Ok`, and `continue` lets us move to the next iteration of the loop; in +effect, this enables us to ignore all errors and continue with our program. + +Now we should be good! Let’s try: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/guessing_game` +Guess the number! +The secret number is: 61 +Please input your guess. +10 +You guessed: 10 +Too small! +Please input your guess. +99 +You guessed: 99 +Too big! +Please input your guess. +foo +Please input your guess. +61 +You guessed: 61 +You win! +``` + +Awesome! With one tiny last tweak, we have finished the guessing game. Can you +think of what it is? That’s right, we don’t want to print out the secret +number. It was good for testing, but it kind of ruins the game. Here’s our +final source: + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + loop { + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + let guess: u32 = match guess.trim().parse() { + Ok(num) => num, + Err(_) => continue, + }; + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => { + println!("You win!"); + break; + } + } + } +} +``` + +## Complete! + +This project showed you a lot: `let`, `match`, methods, associated +functions, using external crates, and more. + +At this point, you have successfully built the Guessing Game! Congratulations! From e16d3b4f66836a7aab06062ffec4fd791d30e882 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 8 Jul 2016 15:49:47 -0400 Subject: [PATCH 052/204] Proposed reordering (without Up and Running chapter for now --- src/SUMMARY.md | 73 -------------------------------------------------- 1 file changed, 73 deletions(-) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 1aab03cbfa..945102e598 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -7,14 +7,6 @@ - [Guessing Game Tutorial](ch02-01-guessing-game-tutorial.md) -- [Up and Running](ch03-01-up-and-running.md) - - [Anatomy of a Rust Program](ch03-02-anatomy-of-a-rust-program.md) - - [Variable Bindings in Detail](ch03-03-variable-bindings-in-detail.md) - - [Data Types in Rust](ch03-04-data-types-in-rust.md) - - [How Functions Work in Rust](ch03-05-how-functions-work-in-rust.md) - - [Comments](ch03-06-comments.md) - - [Control flow](ch03-07-control-flow.md) - - [Understanding Ownership](ch04-01-understanding-ownership.md) - [Ownership](ch04-02-ownership.md) - [References & Borrowing](ch04-03-references-and-borrowing.md) @@ -30,68 +22,3 @@ - [Match](ch06-03-match.md) - [Patterns](ch06-04-patterns.md) - [if let](ch06-05-if-let.md) - -- [Crates & Modules]() - -- [Error Handling]() - -- [Basic Collections]() - - [Vectors]() - - [Strings]() - - [`HashMap`]() - -- [Lifetimes]() - -- [Traits]() - -- [Closures]() - -- [Iterators]() - -- [I/O]() - - [`Read` & `Write`]() - - [`std::fs`]() - - [`std::path`]() - - [`std::env`]() - -- [Testing]() - -- [Smart Pointers]() - - [`Deref`]() - - [`Deref` coercions]() - - [`Box`]() - - [`Rc`]() - -- [Concurrency]() - - [Threads]() - - [`Send` & `Sync`]() - - [`Arc`]() - - [`Mutex`]() - - [`Channels`]() - -- [Unsafe Rust]() - - [Raw Pointers]() - - [transmute]() - -- [FFI]() - - [Conditional Compilation]() - - [Bindings to C]() - - [Using Rust from Other Languages]() - - [`static`]() - -- [Cargo]() - - [Crates.io]() - -- [Advanced Type System Features]() - - [Associated Types]() - - [Trait Objects]() - - [UFCS]() - - [Coherence]() - -- [Interior mutability]() - - [`Cell`]() - - [`RefCell`]() - -- [Macros]() - -- [Nightly Rust]() From e83ec9a5c57d244f2c7bc0fd317570f19f708103 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 8 Jul 2016 15:57:19 -0400 Subject: [PATCH 053/204] Update ch04-02-ownership.md --- src/ch04-02-ownership.md | 51 +++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index cfa7514d8e..ba267f23ff 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -1,37 +1,30 @@ # Ownership -Rust’s central feature is called ‘ownership’. It is a feature that is -straightforward to explain, but has deep implications for the rest of the -language. - -Rust is committed to both safety and speed. One of the key tools for balancing -between them is “zero-cost abstractions”: the various abstractions in Rust do -not pose a global performance penalty. The ownership system is a prime example -of a zero-cost abstraction. All of the analysis we’ll talk about in this guide -is done at compile time. You do not pay any run-time cost for any of these -features. - -However, this system does have a certain cost: learning curve. Many new -Rustaceans experience something we like to call ‘fighting with the borrow -checker’, where the Rust compiler refuses to compile a program that the author -thinks is valid. This can happen because the programmer isn’t used to thinking -carefully about ownership, or is thinking about it differently from the way -that Rust does. You probably will experience something similar at first. There is -good news, however: more experienced Rust developers report that once they work -with the rules of the ownership system for a period of time, they fight the -borrow checker less and less. Keep at it! - -This chapter will give you a foundation for understanding the rest of the -language. To do so, we’re going to learn through examples, focusing on a very -common data structure: strings. +Rust’s central feature is called ‘ownership’. It is a feature that is straightforward +to explain, but has deep implications for the rest of the language. + +All programs have to manage the way they use a computer's memory while running. Some +languages have garbage collection, while in others, the programmer has to explicitly +allocate and free the memory. Rust takes a third approach: memory is managed through +a system of ownership with a set of rules that the compiler checks at compile-time. +You do not pay any run-time cost for any of these features. + +However, because ownership is a new concept for many programmers, it does take some +time to get used to. There is good news, however: the more experienced you become +with Rust, and the rules of the ownership system, the more you'll be able to naturally +develop code that is both safe and efficient. Keep at it! + +Once you understand ownership, you have a good foundation for understanding the +features that make Rust unique. Let's learn ownership by going through someexamples, +focusing on a very common data structure: strings. ## Variable binding scope -Let’s take a step back and look at the very basics again. Now that we’re past -basic syntax, we won’t include all of the `fn main() {` stuff in examples, so -if you’re following along, you will have to put them inside of a `main()` -function. This lets our examples be a bit more concise, letting us focus on the -actual details, rather than boilerplate. +We've walked through an example of a Rust program already in the tutorial chapter. +Now that we’re past basic syntax, we won’t include all of the fn main() { stuff in +examples, so if you’re following along, you will have to put them inside of a main() +function. This lets our examples be a bit more concise, letting us focus on the actual +details rather than boilerplate. Anyway, here it is: From aa8e2305c489358ef3e9809ecaef11fbd6a0d7cd Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 8 Jul 2016 15:58:10 -0400 Subject: [PATCH 054/204] Update ch04-02-ownership.md --- src/ch04-02-ownership.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index ba267f23ff..53b11c02f5 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -15,8 +15,8 @@ with Rust, and the rules of the ownership system, the more you'll be able to nat develop code that is both safe and efficient. Keep at it! Once you understand ownership, you have a good foundation for understanding the -features that make Rust unique. Let's learn ownership by going through someexamples, -focusing on a very common data structure: strings. +features that make Rust unique. In this chapter, we'll learn ownership by going through +some examples, focusing on a very common data structure: strings. ## Variable binding scope From 5c106c9c2350c2e1f7ebf879e2fde0b64bc52709 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 8 Jul 2016 15:58:41 -0400 Subject: [PATCH 055/204] Update ch04-02-ownership.md --- src/ch04-02-ownership.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index 53b11c02f5..82eaeaac4a 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -21,8 +21,8 @@ some examples, focusing on a very common data structure: strings. ## Variable binding scope We've walked through an example of a Rust program already in the tutorial chapter. -Now that we’re past basic syntax, we won’t include all of the fn main() { stuff in -examples, so if you’re following along, you will have to put them inside of a main() +Now that we’re past basic syntax, we won’t include all of the `fn main() {` stuff in +examples, so if you’re following along, you will have to put them inside of a `main()` function. This lets our examples be a bit more concise, letting us focus on the actual details rather than boilerplate. From b3f2d287c79a0db24ff112ba5da13c18fbb3ab43 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 9 Jul 2016 17:09:10 -0400 Subject: [PATCH 056/204] Wording, spelling, whitespace, and punctuation corrections Unrelated to any comment or issue. --- src/ch02-01-guessing-game-tutorial.md | 247 +++++++++++++------------- 1 file changed, 126 insertions(+), 121 deletions(-) diff --git a/src/ch02-01-guessing-game-tutorial.md b/src/ch02-01-guessing-game-tutorial.md index 6ec0fe3922..8e804de0cb 100644 --- a/src/ch02-01-guessing-game-tutorial.md +++ b/src/ch02-01-guessing-game-tutorial.md @@ -4,7 +4,7 @@ Let’s learn some Rust! For our first project, we’ll implement a classic beginner programming problem: the guessing game. Here’s how it works: Our program will generate a random integer between one and a hundred. It will then prompt us to enter a guess. Upon entering our guess, it will tell us if we’re -too low or too high. Once we guess correctly, it will congratulate us. Sounds +too low or too high. Once we guess correctly, it will congratulate us. Sound good? Along the way, we’ll learn a little bit about Rust. The next chapter, ‘Syntax @@ -22,10 +22,10 @@ $ cargo new guessing_game --bin $ cd guessing_game ``` -We pass the name of our project to `cargo new`, and then the `--bin` flag, -since we’re making a binary, rather than a library. +We pass the name of our project to `cargo new`, then the `--bin` flag, since +we’re making a binary, rather than a library. -Check out the generated `Cargo.toml`: +Take a look at the generated `Cargo.toml`: ```toml [package] @@ -48,14 +48,11 @@ fn main() { Let’s try compiling what Cargo gave us: -```{bash} +```bash $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) ``` -Excellent! Open up your `src/main.rs` again. We’ll be writing all of -our code in this file. - Before we move on, let me show you one more Cargo command: `run`. `cargo run` is kind of like `cargo build`, but it also then runs the produced executable. Try it out: @@ -68,15 +65,18 @@ Hello, world! ``` Great! The `run` command comes in handy when you need to rapidly iterate on a -project. Our game is such a project, we need to quickly test each +project. Our game is such a project: we want to quickly test each iteration before moving on to the next one. +Now open up your `src/main.rs` again. We’ll be writing all of our code in this +file. + ## Processing a Guess Let’s get to it! The first thing we need to do for our guessing game is allow our player to input a guess. Put this in your `src/main.rs`: -```rust,no_run +```rust,ignore use std::io; fn main() { @@ -99,12 +99,12 @@ There’s a lot here! Let’s go over it, bit by bit. use std::io; ``` -We’ll need to take user input, and then print the result as output. As such, we +We’ll need to take user input and then print the result as output. As such, we need the `io` library from the standard library. Rust only imports a few things by default into every program, [the ‘prelude’][prelude]. If it’s not in the prelude, you’ll have to `use` it directly. There is also a second ‘prelude’, the -[`io` prelude][ioprelude], which serves a similar function: you import it, and it -imports a number of useful, `io`-related things. +[`io` prelude][ioprelude], which serves a similar function: when you import it, +you get a number of useful, `io`-related things, so that's what we've done here. [prelude]: ../std/prelude/index.html [ioprelude]: ../std/io/prelude/index.html @@ -152,10 +152,10 @@ many languages, this is called a ‘variable’, but Rust’s variable bindings a few tricks up their sleeves. For example, they’re [immutable][immutable] by default. That’s why our example -uses `mut`: it makes a binding mutable, rather than immutable. `let` doesn’t -take a name on the left hand side of the assignment, it actually accepts a -‘[pattern][patterns]’. We’ll use patterns later. It’s easy enough -to use for now: +uses `mut`: it makes a binding mutable, rather than immutable. Also, `let` +doesn’t actually take a name on the left hand side of the assignment, it really +accepts a ‘[pattern][patterns]’. We’ll use more complicated patterns later; for +now, let's use only a name: ```rust let foo = 5; // immutable. @@ -218,7 +218,7 @@ The next part will use this handle to get input from the user: ``` Here, we call the [`read_line()`][read_line] method on our handle. -[Methods][method] are like associated functions, but are only available on a +[Methods][method] are like associated functions but are only available on a particular instance of a type, rather than the type itself. We’re also passing one argument to `read_line()`: `&mut guess`. @@ -244,7 +244,7 @@ the input, it needs to be mutable. But we’re not quite done with this line of code, though. While it’s a single line of text, it’s only the first part of the single logical line of -code: +code. This is the second part of the line: ```rust,ignore .expect("Failed to read line"); @@ -252,7 +252,7 @@ code: When you call a method with the `.foo()` syntax, you may introduce a newline and other whitespace. This helps you split up long lines. We _could_ have -done: +written this code as: ```rust,ignore io::stdin().read_line(&mut guess).expect("failed to read line"); @@ -279,8 +279,7 @@ displaying the message. [expect]: ../std/result/enum.Result.html#method.expect [panic]: error-handling.html -If we leave off calling this method, our program will compile, but -we’ll get a warning: +If we don't call this method, our program will compile, but we’ll get a warning: ```bash $ cargo build @@ -292,14 +291,14 @@ src/main.rs:10 io::stdin().read_line(&mut guess); ``` Rust warns us that we haven’t used the `Result` value. This warning comes from -a special annotation that `io::Result` has. Rust is trying to tell you that -you haven’t handled a possible error. The right way to suppress the error is -to actually write error handling. Luckily, if we want to crash if there’s -a problem, we can use `expect()`. If we can recover from the -error somehow, we’d do something else, but we’ll save that for a future -project. +a special annotation that `io::Result` has. Rust is trying to tell you that you +haven’t handled a possible error. The right way to suppress the error is to +actually write error handling. Luckily, if we want to crash if there’s a +problem, we can use `expect()`. If we can recover from the error somehow, we’d +do something else, but we’ll save that for a future project. -There’s only one line of this first example left: +There’s only one line of this first example left, aside from the closing curly +brace: ```rust,ignore println!("You guessed: {}", guess); @@ -307,8 +306,8 @@ There’s only one line of this first example left: ``` This prints out the string we saved our input in. The `{}`s are a placeholder, -and so we pass it `guess` as an argument. If we had multiple `{}`s, we would -pass multiple arguments: +and we pass `guess` as an argument to the macro. If we had multiple `{}`s, we +would pass multiple arguments: ```rust let x = 5; @@ -317,8 +316,6 @@ let y = 10; println!("x and y: {} and {}", x, y); ``` -Easy. - Anyway, that’s the tour. We can run what we have with `cargo run`: ```bash @@ -331,8 +328,8 @@ Please input your guess. You guessed: 6 ``` -All right! Our first part is done: we can get input from the keyboard, -and then print it back out. +All right! Our first part is done: we can get input from the keyboard and then +print it back out. # Generating a secret number @@ -384,10 +381,10 @@ $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) ``` -(You may see different versions, of course.) +(You may see different versions and the lines may be in a different order.) Lots of new output! Now that we have an external dependency, Cargo fetches the -latest versions of everything from the registry, which is a copy of data from +latest versions of everything from the *registry*, which is a copy of data from [Crates.io][cratesio]. Crates.io is where people in the Rust ecosystem post their open source Rust projects for others to use. @@ -396,7 +393,7 @@ post their open source Rust projects for others to use. After updating the registry, Cargo checks our `[dependencies]` and downloads any we don’t have yet. In this case, while we only said we wanted to depend on `rand`, we’ve also grabbed a copy of `libc`. This is because `rand` depends on -`libc` to work. After downloading them, it compiles them, and then compiles +`libc` to work. After downloading them, it compiles them and then compiles our project. If we run `cargo build` again, we’ll get different output: @@ -405,43 +402,43 @@ If we run `cargo build` again, we’ll get different output: $ cargo build ``` -That’s right, no output! Cargo knows that our project has been built, and that -all of its dependencies are built, and so there’s no reason to do all that -stuff. With nothing to do, it simply exits. If we open up `src/main.rs` again, -make a trivial change, and then save it again, we’ll only see one line: +That’s right, no output! Cargo knows that our project has been built, that +all of its dependencies are built, and that no changes have been made. There’s +no reason to do all that stuff again. With nothing to do, it simply +exits. If we open up `src/main.rs`, make a trivial change, then save it again, +we’ll only see one line: ```bash $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) ``` -So, we told Cargo we wanted any `0.3.x` version of `rand`, and so it fetched the latest -version at the time this was written, `v0.3.8`. But what happens when next -week, version `v0.3.9` comes out, with an important bugfix? While getting -bugfixes is important, what if `0.3.9` contains a regression that breaks our -code? - -The answer to this problem is the `Cargo.lock` file you’ll now find in your -project directory. When you build your project for the first time, Cargo -figures out all of the versions that fit your criteria, and then writes them -to the `Cargo.lock` file. When you build your project in the future, Cargo -will see that the `Cargo.lock` file exists, and then use that specific version -rather than do all the work of figuring out versions again. This lets you -have a repeatable build automatically. In other words, we’ll stay at `0.3.8` -until we explicitly upgrade, and so will anyone who we share our code with, -thanks to the lock file. - -What about when we _do_ want to use `v0.3.9`? Cargo has another command, -`update`, which says ‘ignore the lock, figure out all the latest versions that -fit what we’ve specified. If that works, write those versions out to the lock -file’. But, by default, Cargo will only look for versions larger than `0.3.0` -and smaller than `0.4.0`. If we want to move to `0.4.x`, we’d have to update -the `Cargo.toml` directly. When we do, the next time we `cargo build`, Cargo -will update the index and re-evaluate our `rand` requirements. +What happens when next week version `v0.3.15` of the `rand` crate comes out, +with an important bugfix? While getting bugfixes is important, what if `0.3.15` +contains a regression that breaks our code? + +The answer to this problem is the `Cargo.lock` file created the first time we +ran `cargo build` that is now in your project directory. When you build your +project for the first time, Cargo figures out all of the versions that fit your +criteria then writes them to the `Cargo.lock` file. When you build your project +in the future, Cargo will see that the `Cargo.lock` file exists and then use +that specific version rather than do all the work of figuring out versions +again. This lets you have a repeatable build automatically. In other words, +we’ll stay at `0.3.14` until we explicitly upgrade, and so will anyone who we +share our code with, thanks to the lock file. + +What about when we _do_ want to use `v0.3.15`? Cargo has another command, +`update`, which says ‘ignore the `Cargo.lock` file and figure out all the +latest versions that fit what we’ve specified in `Cargo.toml`. If that works, +write those versions out to the lock file’. But by default, Cargo will only +look for versions larger than `0.3.0` and smaller than `0.4.0`. If we want to +move to `0.4.x`, we’d have to update what is in the `Cargo.toml` file. When we +do, the next time we `cargo build`, Cargo will update the index and re-evaluate +our `rand` requirements. There’s a lot more to say about [Cargo][doccargo] and [its ecosystem][doccratesio], but for now, that’s all we need to know. Cargo makes -it really easy to re-use libraries, and so Rustaceans tend to write smaller +it really easy to re-use libraries, so Rustaceans are able to write smaller projects which are assembled out of a number of sub-packages. [doccargo]: http://doc.crates.io @@ -473,11 +470,11 @@ fn main() { } ``` -The first thing we’ve done is change the first line. It now says -`extern crate rand`. Because we declared `rand` in our `[dependencies]`, we -can use `extern crate` to let Rust know we’ll be making use of it. This also -does the equivalent of a `use rand;` as well, so we can make use of anything -in the `rand` crate by prefixing it with `rand::`. +The first thing we’ve done is change the first line. It now says `extern crate +rand`. Because we declared `rand` in our `[dependencies]`, we can now put +`extern crate` in our code to let Rust know we’ll be making use of that +dependency. This also does the equivalent of a `use rand;` as well, so we can +call anything in the `rand` crate by prefixing it with `rand::`. Next, we added another `use` line: `use rand::Rng`. We’re going to use a method in a moment, and it requires that `Rng` be in scope to work. The basic @@ -497,15 +494,16 @@ There are two other lines we added, in the middle: We use the `rand::thread_rng()` function to get a copy of the random number generator, which is local to the particular [thread][concurrency] of execution -we’re in. Because we `use rand::Rng`’d above, it has a `gen_range()` method -available. This method takes two arguments, and generates a number between -them. It’s inclusive on the lower bound, but exclusive on the upper bound, -so we need `1` and `101` to get a number ranging from one to a hundred. +we’re in. Because we put `use rand::Rng` above, the random number generator has +a `gen_range()` method available. This method takes two numbers as arguments +and generates a random number between them. It’s inclusive on the lower bound +but exclusive on the upper bound, so we need `1` and `101` to ask for a number +ranging from one to a hundred. [concurrency]: concurrency.html The second line prints out the secret number. This is useful while -we’re developing our program, so we can easily test it out. But we’ll be +we’re developing our program to let us easily test it out, but we’ll be deleting it for the final version. It’s not much of a game if it prints out the answer when you start it up! @@ -529,12 +527,13 @@ Please input your guess. You guessed: 5 ``` -Great! Next up: comparing our guess to the secret number. +You should get different random numbers, and they should all be between 1 and +100. Great job! Next up: comparing our guess to the secret number. # Comparing guesses Now that we’ve got user input, let’s compare our guess to the secret number. -Here’s our next step, though it doesn’t quite compile yet: +Here’s part of our next step. It won't quite compile yet though: ```rust,ignore extern crate rand; @@ -568,8 +567,8 @@ fn main() { ``` A few new bits here. The first is another `use`. We bring a type called -`std::cmp::Ordering` into scope. Then, five new lines at the bottom that use -it: +`std::cmp::Ordering` into scope. Then we add five new lines at the bottom that +use that type: ```rust,ignore match guess.cmp(&secret_number) { @@ -600,9 +599,10 @@ With this definition, anything of type `Foo` can be either a namespace for a particular `enum` variant. The [`Ordering`][ordering] `enum` has three possible variants: `Less`, `Equal`, -and `Greater`. The `match` statement takes a value of a type, and lets you -create an ‘arm’ for each possible value. Since we have three types of -`Ordering`, we have three arms: +and `Greater`. The `match` statement takes a value of a type and lets you +create an ‘arm’ for each possible value. An arm is made up of a pattern and the +code that we should execute if the pattern matches the value of the type. Since +we have three types of `Ordering`, we have three arms: ```rust,ignore match guess.cmp(&secret_number) { @@ -615,7 +615,7 @@ match guess.cmp(&secret_number) { [ordering]: ../std/cmp/enum.Ordering.html If it’s `Less`, we print `Too small!`, if it’s `Greater`, `Too big!`, and if -`Equal`, `You win!`. `match` is really useful, and is used often in Rust. +`Equal`, `You win!`. `match` is really useful and is used often in Rust. I did mention that this won’t quite compile yet, though. Let’s try it: @@ -636,15 +636,17 @@ Could not compile `guessing_game`. Whew! This is a big error. The core of it is that we have ‘mismatched types’. Rust has a strong, static type system. However, it also has type inference. When we wrote `let guess = String::new()`, Rust was able to infer that `guess` -should be a `String`, and so it doesn’t make us write out the type. And with -our `secret_number`, there are a number of types which can have a value -between one and a hundred: `i32`, a thirty-two-bit number, or `u32`, an -unsigned thirty-two-bit number, or `i64`, a sixty-four-bit number or others. -So far, that hasn’t mattered, and so Rust defaults to an `i32`. However, here, -Rust doesn’t know how to compare the `guess` and the `secret_number`. They -need to be the same type. Ultimately, we want to convert the `String` we -read as input into a real number type, for comparison. We can do that -with two more lines. Here’s our new program: +should be a `String`, so it doesn’t make us write out the type. With our +`secret_number`, there are a number of types which can have a value between one +and a hundred: `i32`, a thirty-two-bit number, or `u32`, an unsigned +thirty-two-bit number, or `i64`, a sixty-four-bit number or others. So far, +that hasn’t mattered, and so Rust defaults to an `i32`. However, here, Rust +doesn’t know how to compare the `guess` and the `secret_number`. They need to +be the same type. + +Ultimately, we want to convert the `String` we read as input +into a real number type so that we can compare it to the guess numerically. We +can do that with two more lines. Here’s our new program: ```rust,ignore extern crate rand; @@ -690,8 +692,8 @@ The new two lines: Wait a minute, I thought we already had a `guess`? We do, but Rust allows us to ‘shadow’ the previous `guess` with a new one. This is often used in this exact situation, where `guess` starts as a `String`, but we want to convert it -to an `u32`. Shadowing lets us re-use the `guess` name, rather than forcing us -to come up with two unique names like `guess_str` and `guess`, or something +to a `u32`. Shadowing lets us re-use the `guess` name rather than forcing us +to come up with two unique names like `guess_str` and `guess` or something else. We bind `guess` to an expression that looks like something we wrote earlier: @@ -703,15 +705,17 @@ guess.trim().parse() Here, `guess` refers to the old `guess`, the one that was a `String` with our input in it. The `trim()` method on `String`s will eliminate any white space at the beginning and end of our string. This is important, as we had to press the -‘return’ key to satisfy `read_line()`. This means that if we type `5` and hit -return, `guess` looks like this: `5\n`. The `\n` represents ‘newline’, the -enter key. `trim()` gets rid of this, leaving our string with only the `5`. The -[`parse()` method on strings][parse] parses a string into some kind of number. -Since it can parse a variety of numbers, we need to give Rust a hint as to the -exact type of number we want. Hence, `let guess: u32`. The colon (`:`) after -`guess` tells Rust we’re going to annotate its type. `u32` is an unsigned, -thirty-two bit integer. Rust has [a number of built-in number types][number], -but we’ve chosen `u32`. It’s a good default choice for a small positive number. +‘return’ key to satisfy `read_line()`. If we type `5` and hit return, `guess` +looks like this: `5\n`. The `\n` represents ‘newline’, the enter key. `trim()` +gets rid of this, leaving our string with only the `5`. + +The [`parse()` method on strings][parse] parses a string into some kind of +number. Since it can parse a variety of numbers, we need to give Rust a hint as +to the exact type of number we want. Hence, `let guess: u32`. The colon (`:`) +after `guess` tells Rust we’re going to annotate its type. `u32` is an +unsigned, thirty-two bit integer. Rust has [a number of built-in number +types][number], but we’ve chosen `u32`. It’s a good default choice for a small +positive number. [parse]: ../std/primitive.str.html#method.parse [number]: primitive-types.html#numeric-types @@ -736,8 +740,8 @@ Too big! ``` Nice! You can see I even added spaces before my guess, and it still figured -out that I guessed 76. Run the program a few times, and verify that guessing -the number works, as well as guessing a number too small. +out that I guessed 76. Run the program a few times. Verify that guessing +the secret number works, as well as guessing a number too small. Now we’ve got most of the game working, but we can only make one guess. Let’s change that by adding loops! @@ -852,8 +856,8 @@ fn main() { ``` By adding the `break` line after the `You win!`, we’ll exit the loop when we -win. Exiting the loop also means exiting the program, since it’s the last -thing in `main()`. We have only one more tweak to make: when someone inputs a +win. Exiting the loop also means exiting the program, since the loop is the last +thing in `main()`. We have another tweak to make: when someone inputs a non-number, we don’t want to quit, we want to ignore it. We can do that like this: @@ -906,19 +910,20 @@ let guess: u32 = match guess.trim().parse() { Err(_) => continue, }; ``` + This is how you generally move from ‘crash on error’ to ‘actually handle the -error’, by switching from `expect()` to a `match` statement. A `Result` is -returned by `parse()`, this is an `enum` like `Ordering`, but in this case, -each variant has some data associated with it: `Ok` is a success, and `Err` is a -failure. Each contains more information: the successfully parsed integer, or an -error type. In this case, we `match` on `Ok(num)`, which sets the name `num` to -the unwrapped `Ok` value (the integer), and then we return it on the -right-hand side. In the `Err` case, we don’t care what kind of error it is, so -we just use the catch all `_` instead of a name. This catches everything that -isn't `Ok`, and `continue` lets us move to the next iteration of the loop; in -effect, this enables us to ignore all errors and continue with our program. - -Now we should be good! Let’s try: +error’: by switching from `expect()` to a `match` statement. A `Result` is the +return type of `parse()`. `Result` is an `enum` like `Ordering`, but in this +case, each variant has some data associated with it. `Ok` is a success, and +`Err` is a failure. Each contains more information: in this case, the +successfully parsed integer or an error type, respectively. When we `match` an +`Ok(num)`, that pattern sets the name `num` to the value inside the `Ok` (the +integer), and the code we run just returns that integer. In the `Err` case, we +don’t care what kind of error it is, so we just use the catch-all `_` instead +of a name. So for all errors, we run the code `continue`, which lets us move to +the next iteration of the loop, effectively ignoring the errors. + +Now we should be good! Let’s try it: ```bash $ cargo run @@ -942,7 +947,7 @@ You guessed: 61 You win! ``` -Awesome! With one tiny last tweak, we have finished the guessing game. Can you +Awesome! With one tiny last tweak, we can finish the guessing game. Can you think of what it is? That’s right, we don’t want to print out the secret number. It was good for testing, but it kind of ruins the game. Here’s our final source: From d92251971d207c2d18cf23b4c6a664028f03c657 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 12 Jul 2016 13:50:08 -0400 Subject: [PATCH 057/204] `cargo new` now adds the dependencies header to Cargo.toml --- src/ch01-03-hello-world.md | 15 ++++++++++----- src/ch02-01-guessing-game-tutorial.md | 6 ++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/ch01-03-hello-world.md b/src/ch01-03-hello-world.md index 703834177e..302f8fd142 100644 --- a/src/ch01-03-hello-world.md +++ b/src/ch01-03-hello-world.md @@ -248,21 +248,26 @@ Inside this file, type the following information: ```toml [package] - name = "hello_world" version = "0.1.0" -authors = [ "Your name " ] +authors = ["Your name "] + +[dependencies] ``` The first line, `[package]`, indicates that the following statements are configuring a package. As we add more information to this file, we’ll add other sections, but for now, we just have the package configuration. -The other three lines set the three bits of configuration that Cargo needs to +The next three lines set the three bits of configuration that Cargo needs to know to compile your program: its name, what version it is, and who wrote it. +Cargo gets this information from your environment. If it’s not correct, go ahead +and fix that and save the file. -Once you've added this information to the *Cargo.toml* file, save it to finish -creating the configuration file. +The last line, `[dependencies]`, is the start of a section for you to list any +crates that your project will depend on, so that Cargo knows to download and +compile those too. We won't need any other crates for this project, but we will +in the guessing game tutorial in the next chapter. ## Building and Running a Cargo Project diff --git a/src/ch02-01-guessing-game-tutorial.md b/src/ch02-01-guessing-game-tutorial.md index 8e804de0cb..090581047f 100644 --- a/src/ch02-01-guessing-game-tutorial.md +++ b/src/ch02-01-guessing-game-tutorial.md @@ -29,10 +29,11 @@ Take a look at the generated `Cargo.toml`: ```toml [package] - name = "guessing_game" version = "0.1.0" authors = ["Your Name "] + +[dependencies] ``` Cargo gets this information from your environment. If it’s not correct, go ahead @@ -344,7 +345,8 @@ programs. Using external crates is where Cargo really shines. Before we can write the code using `rand`, we need to modify our `Cargo.toml`. Open it up, and -add these few lines at the bottom: +add this line at the bottom beneath the `[dependencies]` section header that +Cargo created for you: ```toml [dependencies] From 810775a0c92c26bd2c08a5f0a8b9ff30d5a6bd65 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 12 Jul 2016 13:58:28 -0400 Subject: [PATCH 058/204] Fix now-inaccurate forward and backward references --- src/ch02-01-guessing-game-tutorial.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/ch02-01-guessing-game-tutorial.md b/src/ch02-01-guessing-game-tutorial.md index 090581047f..e1135be9b1 100644 --- a/src/ch02-01-guessing-game-tutorial.md +++ b/src/ch02-01-guessing-game-tutorial.md @@ -7,14 +7,12 @@ prompt us to enter a guess. Upon entering our guess, it will tell us if we’re too low or too high. Once we guess correctly, it will congratulate us. Sound good? -Along the way, we’ll learn a little bit about Rust. The next chapter, ‘Syntax -and Semantics’, will dive deeper into each part. ## Set up -Let’s set up a new project. Go to your projects directory. Remember how we had -to create our directory structure and a `Cargo.toml` for `hello_world`? Cargo -has a command that does that for us. Let’s give it a shot: +Let’s set up a new project. Go to your projects directory. Remember the end of +the `hello world` example that mentioned `cargo new` to create new cargo +projects? Let’s give it a shot: ```bash $ cd ~/projects @@ -114,7 +112,7 @@ you get a number of useful, `io`-related things, so that's what we've done here. fn main() { ``` -As you’ve seen before, the `main()` function is the entry point into your +As you’ve seen in Chapter 1, the `main()` function is the entry point into the program. The `fn` syntax declares a new function, the `()`s indicate that there are no arguments, and `{` starts the body of the function. Because we didn’t include a return type, it’s assumed to be `()`, an empty @@ -128,7 +126,7 @@ we didn’t include a return type, it’s assumed to be `()`, an empty println!("Please input your guess."); ``` -We previously learned that `println!()` is a [macro][macros] that +We previously learned in Chapter 1 that `println!()` is a [macro][macros] that prints a [string][strings] to the screen. [macros]: macros.html From f1a35cd1ec841059dc24a4ffc404880b5b3f61be Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 12 Jul 2016 14:03:46 -0400 Subject: [PATCH 059/204] Outdent code that's been extracted from its context --- src/ch02-01-guessing-game-tutorial.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ch02-01-guessing-game-tutorial.md b/src/ch02-01-guessing-game-tutorial.md index e1135be9b1..4a34db4eae 100644 --- a/src/ch02-01-guessing-game-tutorial.md +++ b/src/ch02-01-guessing-game-tutorial.md @@ -121,9 +121,9 @@ we didn’t include a return type, it’s assumed to be `()`, an empty [tuples]: primitive-types.html#tuples ```rust,ignore - println!("Guess the number!"); +println!("Guess the number!"); - println!("Please input your guess."); +println!("Please input your guess."); ``` We previously learned in Chapter 1 that `println!()` is a [macro][macros] that @@ -133,7 +133,7 @@ prints a [string][strings] to the screen. [strings]: strings.html ```rust,ignore - let mut guess = String::new(); +let mut guess = String::new(); ``` Now we’re getting interesting! There’s a lot going on in this little line. @@ -190,8 +190,8 @@ a new value of some kind. Let’s move forward: ```rust,ignore - io::stdin().read_line(&mut guess) - .expect("Failed to read line"); +io::stdin().read_line(&mut guess) + .expect("Failed to read line"); ``` That’s a lot more! Let’s go bit-by-bit. The first line has two parts. Here’s @@ -246,7 +246,7 @@ a single line of text, it’s only the first part of the single logical line of code. This is the second part of the line: ```rust,ignore - .expect("Failed to read line"); +.expect("Failed to read line"); ``` When you call a method with the `.foo()` syntax, you may introduce a newline @@ -254,7 +254,7 @@ and other whitespace. This helps you split up long lines. We _could_ have written this code as: ```rust,ignore - io::stdin().read_line(&mut guess).expect("failed to read line"); +io::stdin().read_line(&mut guess).expect("failed to read line"); ``` But that gets hard to read. So we’ve split it up, two lines for two method @@ -487,9 +487,9 @@ details, read the [traits][traits] section. There are two other lines we added, in the middle: ```rust,ignore - let secret_number = rand::thread_rng().gen_range(1, 101); +let secret_number = rand::thread_rng().gen_range(1, 101); - println!("The secret number is: {}", secret_number); +println!("The secret number is: {}", secret_number); ``` We use the `rand::thread_rng()` function to get a copy of the random number @@ -685,8 +685,8 @@ fn main() { The new two lines: ```rust,ignore - let guess: u32 = guess.trim().parse() - .expect("Please type a number!"); +let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); ``` Wait a minute, I thought we already had a `guess`? We do, but Rust allows us From 0cf529ac69acd240771b77087885bd060f439edd Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 12 Jul 2016 14:28:37 -0400 Subject: [PATCH 060/204] Update rand crate version used to the current latest --- src/ch02-01-guessing-game-tutorial.md | 30 +++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/ch02-01-guessing-game-tutorial.md b/src/ch02-01-guessing-game-tutorial.md index 4a34db4eae..1527adebe6 100644 --- a/src/ch02-01-guessing-game-tutorial.md +++ b/src/ch02-01-guessing-game-tutorial.md @@ -349,22 +349,22 @@ Cargo created for you: ```toml [dependencies] -rand="0.3.0" +rand = "0.3.14" ``` The `[dependencies]` section of `Cargo.toml` is like the `[package]` section: everything that follows it is part of it, until the next section starts. Cargo uses the dependencies section to know what dependencies on external -crates you have, and what versions you require. In this case, we’ve specified version `0.3.0`, -which Cargo understands to be any release that’s compatible with this specific version. -Cargo understands [Semantic Versioning][semver], which is a standard for writing version -numbers. A bare number like above is actually shorthand for `^0.3.0`, -meaning "anything compatible with 0.3.0". -If we wanted to use only `0.3.0` exactly, we could say `rand="=0.3.0"` -(note the two equal signs). -And if we wanted to use the latest version we could use `*`. -We could also use a range of versions. -[Cargo’s documentation][cargodoc] contains more details. +crates you have, and what versions you require. In this case, we’ve specified +version `0.3.14`, which Cargo understands to be any release that’s compatible +with this specific version. Cargo understands [Semantic Versioning][semver], +which is a standard for writing versio numbers. A bare number like above is +actually shorthand for `^0.3.14`, meaning "anything compatible with 0.3.14". +If we wanted to use only `0.3.14` exactly, we could say `rand = "=0.3.14"` +(note the equal sign within the version string). And if we wanted to use +whatever the latest version currently is, we could use `*`. We could also use a +range of versions. [Cargo’s documentation][cargodoc] contains more details +about the different ways to specify dependencies. [semver]: http://semver.org [cargodoc]: http://doc.crates.io/crates-io.html @@ -374,10 +374,10 @@ Now, without changing any of our code, let’s build our project: ```bash $ cargo build Updating registry `https://github.com/rust-lang/crates.io-index` - Downloading rand v0.3.8 - Downloading libc v0.1.6 - Compiling libc v0.1.6 - Compiling rand v0.3.8 + Downloading rand v0.3.14 + Downloading libc v0.2.14 + Compiling libc v0.2.14 + Compiling rand v0.3.14 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) ``` From 7e85e67d11013fa4b14aefd9ca69608bf7333b04 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 12 Jul 2016 14:42:09 -0400 Subject: [PATCH 061/204] Clarify semver paragraphs a bit --- src/ch02-01-guessing-game-tutorial.md | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ch02-01-guessing-game-tutorial.md b/src/ch02-01-guessing-game-tutorial.md index 1527adebe6..fec8b7a5cc 100644 --- a/src/ch02-01-guessing-game-tutorial.md +++ b/src/ch02-01-guessing-game-tutorial.md @@ -353,18 +353,20 @@ rand = "0.3.14" ``` The `[dependencies]` section of `Cargo.toml` is like the `[package]` section: -everything that follows it is part of it, until the next section starts. -Cargo uses the dependencies section to know what dependencies on external -crates you have, and what versions you require. In this case, we’ve specified -version `0.3.14`, which Cargo understands to be any release that’s compatible -with this specific version. Cargo understands [Semantic Versioning][semver], -which is a standard for writing versio numbers. A bare number like above is -actually shorthand for `^0.3.14`, meaning "anything compatible with 0.3.14". -If we wanted to use only `0.3.14` exactly, we could say `rand = "=0.3.14"` -(note the equal sign within the version string). And if we wanted to use -whatever the latest version currently is, we could use `*`. We could also use a -range of versions. [Cargo’s documentation][cargodoc] contains more details -about the different ways to specify dependencies. +everything that follows the section heading is part of that section, until +another section starts. Cargo uses the dependencies section to know what +dependencies on external crates you have and what versions of those crates you +require. In this case, we’ve specified the `rand` crate with the semantic +version specifier `0.3.14`. + +Cargo understands [Semantic Versioning][semver], which is a standard for +writing version numbers. A bare number like above is actually shorthand for +`^0.3.14`, which means "any version that has a public API compatible with +version 0.3.14". If we wanted to use only `0.3.14` exactly, we could say `rand += "=0.3.14"` (note the equal sign within the version string). And if we wanted +to use whatever the latest version currently is, we could use `*`. [Cargo’s +documentation][cargodoc] contains more details and other ways to specify +dependencies. [semver]: http://semver.org [cargodoc]: http://doc.crates.io/crates-io.html From 64eb26fb028434be0c89bd1c254cb946cb59aea5 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 12 Jul 2016 15:08:02 -0400 Subject: [PATCH 062/204] Update cargo output --- src/ch02-01-guessing-game-tutorial.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ch02-01-guessing-game-tutorial.md b/src/ch02-01-guessing-game-tutorial.md index fec8b7a5cc..1e7601fb5a 100644 --- a/src/ch02-01-guessing-game-tutorial.md +++ b/src/ch02-01-guessing-game-tutorial.md @@ -624,13 +624,12 @@ I did mention that this won’t quite compile yet, though. Let’s try it: ```bash $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) -src/main.rs:28:21: 28:35 error: mismatched types: - expected `&collections::string::String`, - found `&_` -(expected struct `collections::string::String`, - found integral variable) [E0308] -src/main.rs:28 match guess.cmp(&secret_number) { +src/main.rs:23:21: 23:35 error: mismatched types [E0308] +src/main.rs:23 match guess.cmp(&secret_number) { ^~~~~~~~~~~~~~ +src/main.rs:23:21: 23:35 help: run `rustc --explain E0308` to see a detailed explanation +src/main.rs:23:21: 23:35 note: expected type `&std::string::String` +src/main.rs:23:21: 23:35 note: found type `&_` error: aborting due to previous error Could not compile `guessing_game`. ``` @@ -812,7 +811,9 @@ You guessed: 59 You win! Please input your guess. quit -thread 'main' panicked at 'Please type a number!' +thread 'main' panicked at 'Please type a number!: ParseIntError { kind: InvalidDigit }', src/libcore/result.rs:785 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +error: Process didn't exit successfully: `target/debug/guess` (exit code: 101) ``` Ha! `quit` actually quits. As does any other non-number input. Well, this is From 60c9abaf39a217668ef0cb86fc176d8842a30d52 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 12 Jul 2016 15:51:41 -0400 Subject: [PATCH 063/204] Fix the levels of some of the headings --- src/ch02-01-guessing-game-tutorial.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ch02-01-guessing-game-tutorial.md b/src/ch02-01-guessing-game-tutorial.md index 1e7601fb5a..b4c6738e6d 100644 --- a/src/ch02-01-guessing-game-tutorial.md +++ b/src/ch02-01-guessing-game-tutorial.md @@ -330,7 +330,7 @@ You guessed: 6 All right! Our first part is done: we can get input from the keyboard and then print it back out. -# Generating a secret number +## Generating a secret number Next, we need to generate a secret number. Rust does not yet include random number functionality in its standard library. The Rust team does, however, @@ -532,7 +532,7 @@ You guessed: 5 You should get different random numbers, and they should all be between 1 and 100. Great job! Next up: comparing our guess to the secret number. -# Comparing guesses +## Comparing guesses Now that we’ve got user input, let’s compare our guess to the secret number. Here’s part of our next step. It won't quite compile yet though: @@ -747,7 +747,7 @@ the secret number works, as well as guessing a number too small. Now we’ve got most of the game working, but we can only make one guess. Let’s change that by adding loops! -# Looping +## Looping The `loop` keyword gives us an infinite loop. Let’s add that in: From da2dd5b09fdbb6f65a69a9f725be9d097a28443e Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 12 Jul 2016 16:04:18 -0400 Subject: [PATCH 064/204] Remove or change all forward refs to "Chapter XX" --- src/ch02-01-guessing-game-tutorial.md | 92 +++++++++++---------------- 1 file changed, 36 insertions(+), 56 deletions(-) diff --git a/src/ch02-01-guessing-game-tutorial.md b/src/ch02-01-guessing-game-tutorial.md index b4c6738e6d..80d3c72780 100644 --- a/src/ch02-01-guessing-game-tutorial.md +++ b/src/ch02-01-guessing-game-tutorial.md @@ -116,9 +116,7 @@ As you’ve seen in Chapter 1, the `main()` function is the entry point into the program. The `fn` syntax declares a new function, the `()`s indicate that there are no arguments, and `{` starts the body of the function. Because we didn’t include a return type, it’s assumed to be `()`, an empty -[tuple][tuples]. - -[tuples]: primitive-types.html#tuples +tuple. We will go over tuples in Chapter XX. ```rust,ignore println!("Guess the number!"); @@ -126,48 +124,36 @@ println!("Guess the number!"); println!("Please input your guess."); ``` -We previously learned in Chapter 1 that `println!()` is a [macro][macros] that -prints a [string][strings] to the screen. - -[macros]: macros.html -[strings]: strings.html +We previously learned in Chapter 1 that `println!()` is a macro that +prints a string to the screen. ```rust,ignore let mut guess = String::new(); ``` Now we’re getting interesting! There’s a lot going on in this little line. -The first thing to notice is that this is a [let statement][let], which is -used to create ‘variable bindings’. They take this form: +The first thing to notice is that this is a let statement, which is +used to create ‘variable bindings’. Variable bindings will be covered in more +detail in Chapter XX. Here's an example: ```rust,ignore let foo = bar; ``` -[let]: variable-bindings.html - This will create a new binding named `foo`, and bind it to the value `bar`. In many languages, this is called a ‘variable’, but Rust’s variable bindings have a few tricks up their sleeves. -For example, they’re [immutable][immutable] by default. That’s why our example -uses `mut`: it makes a binding mutable, rather than immutable. Also, `let` -doesn’t actually take a name on the left hand side of the assignment, it really -accepts a ‘[pattern][patterns]’. We’ll use more complicated patterns later; for -now, let's use only a name: +For example, they’re immutable by default. That’s why our example +uses `mut`: it makes a binding mutable, rather than immutable. ```rust let foo = 5; // immutable. let mut bar = 5; // mutable ``` -[immutable]: mutability.html -[patterns]: patterns.html - Oh, and `//` will start a comment, until the end of the line. Rust ignores -everything in [comments][comments]. - -[comments]: comments.html +everything in comments. So now we know that `let mut guess` will introduce a mutable binding named `guess`, but we have to look at the other side of the `=` for what it’s @@ -216,30 +202,28 @@ The next part will use this handle to get input from the user: .read_line(&mut guess) ``` -Here, we call the [`read_line()`][read_line] method on our handle. -[Methods][method] are like associated functions but are only available on a -particular instance of a type, rather than the type itself. We’re also passing -one argument to `read_line()`: `&mut guess`. +Here, we call the [`read_line()`][read_line] method on our handle. Methods are +like associated functions but are only available on a particular instance of a +type, rather than the type itself. We'll talk more about methods in Chapter XX. +We’re also passing one argument to `read_line()`: `&mut guess`. [read_line]: ../std/io/struct.Stdin.html#method.read_line -[method]: method-syntax.html Remember how we bound `guess` above? We said it was mutable. However, `read_line` doesn’t take a `String` as an argument: it takes a `&mut String`. -Rust has a feature called ‘[references][references]’, which allows you to have -multiple references to one piece of data, which can reduce copying. References -are a complex feature, as one of Rust’s major selling points is how safe and -easy it is to use references. We don’t need to know a lot of those details to -finish our program right now, though. For now, all we need to know is that -like `let` bindings, references are immutable by default. Hence, we need to -write `&mut guess`, rather than `&guess`. +The `&` is the feature of Rust called a ‘reference’, which allows you to have +multiple ways to access one piece of data in order to reduce copying. +References are a complex feature, as one of Rust’s major selling points is how +safe and easy it is to use references. We don’t need to know a lot of those +details to finish our program right now, though; Chapter XX will cover them in +more detail. For now, all we need to know is that like `let` bindings, +references are immutable by default. Hence, we need to write `&mut guess`, +rather than `&guess`. Why does `read_line()` take a mutable reference to a string? Its job is -to take what the user types into standard input, and place that into a +to take what the user types into standard input and place that into a string. So it takes that string as an argument, and in order to add -the input, it needs to be mutable. - -[references]: references-and-borrowing.html +the input, that string needs to be mutable. But we’re not quite done with this line of code, though. While it’s a single line of text, it’s only the first part of the single logical line of @@ -271,12 +255,11 @@ sub-libraries, like `io::Result`. The purpose of these `Result` types is to encode error handling information. Values of the `Result` type, like any type, have methods defined on them. In this case, `io::Result` has an [`expect()` method][expect] that takes a value -it’s called on, and if it isn’t a successful one, [`panic!`][panic]s with a +it’s called on, and if it isn’t a successful one, `panic!`s with a message you passed it. A `panic!` like this will cause our program to crash, displaying the message. [expect]: ../std/result/enum.Result.html#method.expect -[panic]: error-handling.html If we don't call this method, our program will compile, but we’ll get a warning: @@ -369,7 +352,7 @@ documentation][cargodoc] contains more details and other ways to specify dependencies. [semver]: http://semver.org -[cargodoc]: http://doc.crates.io/crates-io.html +[cargodoc]: http://doc.crates.io/specifying-dependencies.html Now, without changing any of our code, let’s build our project: @@ -383,7 +366,8 @@ $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) ``` -(You may see different versions and the lines may be in a different order.) +You may see different versions (but they will be compatible, thanks to semver!) +and the lines may be in a different order. Lots of new output! Now that we have an external dependency, Cargo fetches the latest versions of everything from the *registry*, which is a copy of data from @@ -439,9 +423,10 @@ do, the next time we `cargo build`, Cargo will update the index and re-evaluate our `rand` requirements. There’s a lot more to say about [Cargo][doccargo] and [its -ecosystem][doccratesio], but for now, that’s all we need to know. Cargo makes -it really easy to re-use libraries, so Rustaceans are able to write smaller -projects which are assembled out of a number of sub-packages. +ecosystem][doccratesio] that we will get into in Chapter XX, but for now, +that’s all we need to know. Cargo makes it really easy to re-use libraries, so +Rustaceans are able to write smaller projects which are assembled out of a +number of sub-packages. [doccargo]: http://doc.crates.io [doccratesio]: http://doc.crates.io/crates-io.html @@ -482,9 +467,7 @@ Next, we added another `use` line: `use rand::Rng`. We’re going to use a method in a moment, and it requires that `Rng` be in scope to work. The basic idea is this: methods are defined on something called ‘traits’, and for the method to work, it needs the trait to be in scope. For more about the -details, read the [traits][traits] section. - -[traits]: traits.html +details, read the traits section in Chapter XX. There are two other lines we added, in the middle: @@ -495,15 +478,13 @@ println!("The secret number is: {}", secret_number); ``` We use the `rand::thread_rng()` function to get a copy of the random number -generator, which is local to the particular [thread][concurrency] of execution +generator, which is local to the particular thread of execution we’re in. Because we put `use rand::Rng` above, the random number generator has a `gen_range()` method available. This method takes two numbers as arguments and generates a random number between them. It’s inclusive on the lower bound but exclusive on the upper bound, so we need `1` and `101` to ask for a number ranging from one to a hundred. -[concurrency]: concurrency.html - The second line prints out the secret number. This is useful while we’re developing our program to let us easily test it out, but we’ll be deleting it for the final version. It’s not much of a game if it prints out @@ -714,12 +695,11 @@ The [`parse()` method on strings][parse] parses a string into some kind of number. Since it can parse a variety of numbers, we need to give Rust a hint as to the exact type of number we want. Hence, `let guess: u32`. The colon (`:`) after `guess` tells Rust we’re going to annotate its type. `u32` is an -unsigned, thirty-two bit integer. Rust has [a number of built-in number -types][number], but we’ve chosen `u32`. It’s a good default choice for a small -positive number. +unsigned, thirty-two bit integer. Rust has a number of built-in number +types, but we’ve chosen `u32`. It’s a good default choice for a small +positive number. You'll see the other number types in Chapter XX. [parse]: ../std/primitive.str.html#method.parse -[number]: primitive-types.html#numeric-types Just like `read_line()`, our call to `parse()` could cause an error. What if our string contained `A👍%`? There’d be no way to convert that to a number. As From 35bb02632c79591ceb9e3a6adf275886adcdfad4 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 14 Jul 2016 14:39:07 -0400 Subject: [PATCH 065/204] Hard wrap ch 4 to 80 chars for consistency hobgoblin --- src/ch04-02-ownership.md | 74 +++++++++++++------------ src/ch04-03-references-and-borrowing.md | 12 ++-- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index bde9407094..9547ace39d 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -1,30 +1,32 @@ # Ownership -Rust’s central feature is called ‘ownership’. It is a feature that is straightforward -to explain, but has deep implications for the rest of the language. - -All programs have to manage the way they use a computer's memory while running. Some -languages have garbage collection, while in others, the programmer has to explicitly -allocate and free the memory. Rust takes a third approach: memory is managed through -a system of ownership with a set of rules that the compiler checks at compile-time. -You do not pay any run-time cost for any of these features. - -However, because ownership is a new concept for many programmers, it does take some -time to get used to. There is good news, however: the more experienced you become -with Rust, and the rules of the ownership system, the more you'll be able to naturally -develop code that is both safe and efficient. Keep at it! +Rust’s central feature is called ‘ownership’. It is a feature that is +straightforward to explain, but has deep implications for the rest of the +language. + +All programs have to manage the way they use a computer's memory while running. +Some languages have garbage collection, while in others, the programmer has to +explicitly allocate and free the memory. Rust takes a third approach: memory is +managed through a system of ownership with a set of rules that the compiler +checks at compile-time. You do not pay any run-time cost for any of these +features. + +However, because ownership is a new concept for many programmers, it does take +some time to get used to. There is good news, however: the more experienced you +become with Rust, and the rules of the ownership system, the more you'll be +able to naturally develop code that is both safe and efficient. Keep at it! Once you understand ownership, you have a good foundation for understanding the -features that make Rust unique. In this chapter, we'll learn ownership by going through -some examples, focusing on a very common data structure: strings. +features that make Rust unique. In this chapter, we'll learn ownership by going +through some examples, focusing on a very common data structure: strings. ## Variable binding scope -We've walked through an example of a Rust program already in the tutorial chapter. -Now that we’re past basic syntax, we won’t include all of the `fn main() {` stuff in -examples, so if you’re following along, you will have to put them inside of a `main()` -function. This lets our examples be a bit more concise, letting us focus on the actual -details rather than boilerplate. +We've walked through an example of a Rust program already in the tutorial +chapter. Now that we’re past basic syntax, we won’t include all of the `fn +main() {` stuff in examples, so if you’re following along, you will have to put +them inside of a `main()` function. This lets our examples be a bit more +concise, letting us focus on the actual details rather than boilerplate. Anyway, here it is: @@ -53,12 +55,12 @@ on top of this understanding by introducing a new type: `String`. ## Strings -String literals are convenient, but they aren’t the only way that you use strings. -For one thing, they’re immutable. For another, not every string is literal: -what about taking user input and storing it in a string? +String literals are convenient, but they aren’t the only way that you use +strings. For one thing, they’re immutable. For another, not every string is +literal: what about taking user input and storing it in a string? -For this, Rust has a second string type, `String`. You can create a `String` from -a string literal using the `from` function: +For this, Rust has a second string type, `String`. You can create a `String` +from a string literal using the `from` function: ```rust let s = String::from("hello"); @@ -119,10 +121,10 @@ Rust takes a different path. Remember our example? Here’s a version with } // this scope is now over, and s is no longer valid ``` -We have a natural point at which we can return the memory our `String` needs back -to the operating system: when it goes out of scope! When a variable goes out of -scope, a special function is called. This function is called `drop()`, and it -is where the author of `String` can put the code to return the memory. +We have a natural point at which we can return the memory our `String` needs +back to the operating system: when it goes out of scope! When a variable goes +out of scope, a special function is called. This function is called `drop()`, +and it is where the author of `String` can put the code to return the memory. > Aside: This pattern is sometimes called “Resource Acquisition Is > Initialization” in C++, or “RAII” for short. While they are very similar, @@ -233,7 +235,8 @@ but the original variable binding is no longer usable. That solves our problem: s1 and s2 to the same place -With only `s2` valid, when it goes out of scope, it will free the memory, and we’re done! +With only `s2` valid, when it goes out of scope, it will free the memory, and +we’re done! ## Ownership Rules @@ -305,10 +308,10 @@ implemented `drop()`. If you need to do something special when the value goes out of scope, being `Copy` will be an error. So what types are `Copy`? You can check the documentation for the given type to -be sure, but as a rule of thumb, any group of simple scalar values can be -Copy, but nothing that requires allocation or is some form of resource is `Copy`. -And you can’t get it wrong: the compiler will throw an error if you try to use -a type that moves incorrectly, as we saw above. +be sure, but as a rule of thumb, any group of simple scalar values can be Copy, +but nothing that requires allocation or is some form of resource is `Copy`. And +you can’t get it wrong: the compiler will throw an error if you try to use a +type that moves incorrectly, as we saw above. Here’s some types that you’ve seen so far that are `Copy`: @@ -456,4 +459,5 @@ fn calculate_length(s: String) -> (String, usize) { This is too much ceremony: we have to use a tuple to give back the `String` as well as the length. It’s a lot of work for a pattern that should be common. -Luckily for us, Rust has such a feature, and it’s what the next section is about. +Luckily for us, Rust has such a feature, and it’s what the next section is +about. diff --git a/src/ch04-03-references-and-borrowing.md b/src/ch04-03-references-and-borrowing.md index b53dca7e49..113215534b 100644 --- a/src/ch04-03-references-and-borrowing.md +++ b/src/ch04-03-references-and-borrowing.md @@ -112,8 +112,8 @@ Here’s the error: ^~~~~~~~~~~ ``` -Just like bindings are immutable by default, so are references. We’re not allowed -to modify something we have a reference to. +Just like bindings are immutable by default, so are references. We’re not +allowed to modify something we have a reference to. ## Mutable references @@ -131,8 +131,9 @@ fn change(some_string: &mut String) { } ``` -First, we had to change `s` to be `mut`. Then, we had to create a mutable reference -with `&mut s` and accept a mutable reference with `some_string: &mut String`. +First, we had to change `s` to be `mut`. Then, we had to create a mutable +reference with `&mut s` and accept a mutable reference with `some_string: &mut +String`. Mutable references have one big restriction, though. This code fails: @@ -180,7 +181,8 @@ let mut s = String::from("hello"); let r2 = &mut s; ``` -There is a similar rule for combining the two kinds of references. This code errors: +There is a similar rule for combining the two kinds of references. This code +errors: ```rust,ignore let mut s = String::from("hello"); From 72ec43263b5b6f3c8b24a722b1bf44b19fbd0b7d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 14 Jul 2016 14:39:32 -0400 Subject: [PATCH 066/204] Fix references that are now invalid with the rearranging --- src/ch04-01-understanding-ownership.md | 7 +++---- src/ch04-02-ownership.md | 5 ----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/ch04-01-understanding-ownership.md b/src/ch04-01-understanding-ownership.md index 2b2eb43320..ba39afe4ed 100644 --- a/src/ch04-01-understanding-ownership.md +++ b/src/ch04-01-understanding-ownership.md @@ -1,6 +1,5 @@ # Understanding Ownership -Now that we’ve got some basic syntax under our belt, it’s time to take a look -at Rust’s most unique feature: ownership. We’ll also talk about several related -features: borrowing, slices, and lifetimes, as well as how Rust lays things out -in memory. +Now let's look at Rust’s most unique feature: ownership. We’ll also talk about +several related features: borrowing, slices, and lifetimes, as well as how Rust +lays things out in memory. diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index 9547ace39d..aaaea2a3bb 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -168,11 +168,6 @@ the `String` is currently using. The capacity is the total amount of memory the and capacity matters, but not in this context, so don’t worry about it too much if it doesn’t make sense, and just ignore the capacity. -> We’ve talked about two kinds of composite types: arrays and tuples. `String` -> is a third type: a `struct`, which we will cover the details of in the next -> chapter of the book. For now, thinking about `String` as a tuple is close -> enough. - When we assign `s1` to `s2`, the `String` itself is copied. But not all kinds of copying are the same. Many people draw distinctions between ‘shallow copying’ and ‘deep copying’. We don’t use these terms in Rust. We instead say From ffd50bcda5b61c5960e924b780a945d4fd63113f Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 14 Jul 2016 14:42:50 -0400 Subject: [PATCH 067/204] Wording, spelling, whitespace, and punctuation corrections --- src/ch04-02-ownership.md | 100 ++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 44 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index aaaea2a3bb..1c44aca0ad 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -12,8 +12,8 @@ checks at compile-time. You do not pay any run-time cost for any of these features. However, because ownership is a new concept for many programmers, it does take -some time to get used to. There is good news, however: the more experienced you -become with Rust, and the rules of the ownership system, the more you'll be +some time to get used to. There is good news, though: the more experienced you +become with Rust and the rules of the ownership system, the more you'll be able to naturally develop code that is both safe and efficient. Keep at it! Once you understand ownership, you have a good foundation for understanding the @@ -28,17 +28,18 @@ main() {` stuff in examples, so if you’re following along, you will have to pu them inside of a `main()` function. This lets our examples be a bit more concise, letting us focus on the actual details rather than boilerplate. -Anyway, here it is: +Anyway, here is our first example: ```rust let s = "hello"; ``` -This variable binding refers to a string literal. It’s valid from the point at -which it’s declared, until the end of the current _scope_. That is: +This variable binding refers to a string literal, where the value of the string +is hard coded into the text of our program. The binding is valid from the point +at which it’s declared until the end of the current _scope_. That is: ```rust -{ // s is not valid here, it’s not yet in scope +{ // s is not valid here, it’s not yet declared let s = "hello"; // s is valid from this point forward // do stuff with s @@ -77,6 +78,8 @@ This kind of string can be mutated: let mut s = String::from("hello"); s.push_str(", world!"); + +println!("{}", s); // This will print `hello, world!` ``` ## Memory and allocation @@ -87,11 +90,13 @@ cannot? The difference comes down to how these two types deal with memory. In the case of a string literal, because we know the contents of the string at compile time, we can hard-code the text of the string directly into the final executable. This means that string literals are quite fast and efficient. But -these properties only come from its immutability; we can’t put an -arbitrary-sized blob of memory into the binary for each string! +these properties only come from its immutability. We can’t put a blob of memory +into the binary for each string whose size is unknown at compile time and whose +size might change over the course of running the program! -With `String`, to support a mutable, growable string, we need to allocate an -unknown amount of memory to hold the contents. This means two things: +With `String`, in order to support a mutable, growable string, we need to +allocate an unknown amount of memory to hold the contents. This means two +things: 1. The memory must be requested from the operating system at runtime. 2. We need a way of giving this memory back to the operating system when we’re @@ -102,13 +107,15 @@ implementation requests the memory it needs. This is pretty much universal in programming languages. The second case, however, is different. In languages with a garbage collector -(‘GC’), the GC handles that second case, and we, as the programmer, don’t need -to think about it. Without GC, it’s the programmer’s responsibility to identify -when memory is no longer being used, and explicitly return it, just as it was -requested. Doing this correctly has historically been a difficult problem. If -we forget, we will waste memory. If we do it too early, we will have an invalid -variable. If we do it twice, that’s a bug too. We need to pair exactly one -`allocate()` with exactly one `free()`. +(‘GC’), the GC will keep track and clean up memory that isn't being used +anymore, and we, as the programmer, don’t need to think about it. Without GC, +it’s our responsibility to identify when memory is no longer being used and +call code to explicitly return it, just as we did to request it. Doing this +correctly has historically been a difficult problem. If we forget, we will +waste memory. If we do it too early, we will have an invalid variable. If we do +it twice, that’s a bug too. We need to pair exactly one `allocate()` with +exactly one `free()`. + Rust takes a different path. Remember our example? Here’s a version with `String`: @@ -123,8 +130,9 @@ Rust takes a different path. Remember our example? Here’s a version with We have a natural point at which we can return the memory our `String` needs back to the operating system: when it goes out of scope! When a variable goes -out of scope, a special function is called. This function is called `drop()`, -and it is where the author of `String` can put the code to return the memory. +out of scope, Rust calls a special function for us. This function is called +`drop()`, and it is where the author of `String` can put the code to return the +memory. > Aside: This pattern is sometimes called “Resource Acquisition Is > Initialization” in C++, or “RAII” for short. While they are very similar, @@ -165,14 +173,15 @@ A `String` is made up of three parts: a pointer to the memory that holds the contents of the string, a length, and a capacity. The length is how much memory the `String` is currently using. The capacity is the total amount of memory the `String` has gotten from the operating system. The difference between length -and capacity matters, but not in this context, so don’t worry about it too much -if it doesn’t make sense, and just ignore the capacity. +and capacity matters but not in this context, so don’t worry about it too much. +For right now, it's fine to ignore the capacity. -When we assign `s1` to `s2`, the `String` itself is copied. But not all kinds -of copying are the same. Many people draw distinctions between ‘shallow -copying’ and ‘deep copying’. We don’t use these terms in Rust. We instead say -that something is ‘moved’ or ‘cloned’. Assignment in Rust causes a ‘move’. In -other words, it looks like this: +When we assign `s1` to `s2`, the `String` itself is copied, meaning we copy the +pointer, the length, and the capacity. We do not copy the data that the +`String`'s pointer refers to. Many people draw distinctions between ‘shallow +copying’ and ‘deep copying’, and would call this a ‘shallow copy’. We don’t use +these terms in Rust; we instead say that something is ‘moved’ or ‘cloned’. +Assignment in Rust causes a ‘move’. In other words, it looks like this: s1 and s2 @@ -180,31 +189,34 @@ _Not_ this: s1 and s2 to two places -When moving, Rust makes a copy of the data structure itself, the contents of +When moving, Rust makes a copy of the data structure itself. The contents of `s1` are copied, but if `s1` contains a reference, like it does in this case, Rust will not copy the things that those references refer to. -There’s a problem here! Both `data` pointers are pointing to the same place. +There’s a problem here! Both data pointers are pointing to the same place. Why is this a problem? Well, when `s2` goes out of scope, it will free the -memory that `data` points to. And then `s1` goes out of scope, and it will -_also_ try to free the memory that `data` points to! That’s bad. - -So what’s the solution? Here, we stand at a crossroads. There are a few -options. One would be to declare that assignment will also copy out any data. -This works, but is inefficient: what if our `String` contained a novel? Also, -it only works for memory. What if, instead of a `String`, we had a -`TcpConnection`? Opening and closing a network connection is very similar to -allocating and freeing memory. The solution that we could use there is to allow -the programmer to hook into the assignment, similar to `drop()`, and write code -fix things up. That would work, but now, an `=` can run arbitrary code. That’s -also not good, and it doesn’t solve our efficiency concerns either. +memory that the pointer points to. And then `s1` goes out of scope, and it will +_also_ try to free the memory that the pointer points to! That’s bad. + +So what’s the solution? Here, we stand at a crossroads with a few options. One +would be to declare that assignment will also copy out any data. This works, +but is inefficient: what if our `String` contained a novel? Also, it only works +for memory. What if, instead of a `String`, we had a `TcpConnection`? Opening +and closing a network connection is very similar to allocating and freeing +memory, so it would be nice to be able to use the same mechanism, but we can't +because . The solution that we could use there is to +allow the programmer to hook into the assignment, similar to `drop()`, and +write code to fix things up. That would work, but now, an `=` can run arbitrary +code. That’s also not good, and it doesn’t solve our efficiency concerns either. Let’s take a step back: the root of the problem is that `s1` and `s2` both -think that they have control of the memory, and therefore needs to free it. +think that they have control of the memory and therefore need to free it. Instead of trying to copy the allocated memory, we could say that `s1` is no -longer valid, and therefore, doesn’t need to free anything. This is in fact the -choice that Rust makes. Check it out what happens when you try to use `s1` -after `s2` is created: +longer valid and, therefore, doesn’t need to free anything. This is in fact the +choice that Rust makes. Check out what happens when you try to use `s1` after +`s2` is created: ```rust,ignore let s1 = String::from("hello"); From 252f73b0d4395f04fbd002e49e0416e8490d3c71 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 14 Jul 2016 15:43:44 -0400 Subject: [PATCH 068/204] Don't confuse namespace scope with lexical scope right now --- src/ch04-02-ownership.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index 1c44aca0ad..f700a8863d 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -67,10 +67,10 @@ from a string literal using the `from` function: let s = String::from("hello"); ``` -We haven’t seen the double colon (`::`) syntax yet. It is a kind of scope -operator, allowing us to namespace this particular `from()` function under the -`String` type itself, rather than using some sort of name like `string_from()`. -We’ll discuss this syntax more in the “Method Syntax” and “Modules” chapters. +We haven’t seen the double colon (`::`) syntax yet. It is an operator that +allows us to namespace this particular `from()` function under the `String` +type itself, rather than using some sort of name like `string_from()`. We’ll +discuss this syntax more in the “Method Syntax” and “Modules” chapters. This kind of string can be mutated: From ba7bff20ae7a415ddd119b10302b6a3c170ce9db Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 14 Jul 2016 16:29:57 -0400 Subject: [PATCH 069/204] Wording, spelling, whitespace, and punctuation corrections --- src/ch04-02-ownership.md | 62 ++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index f700a8863d..d176da7afd 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -193,10 +193,11 @@ When moving, Rust makes a copy of the data structure itself. The contents of `s1` are copied, but if `s1` contains a reference, like it does in this case, Rust will not copy the things that those references refer to. -There’s a problem here! Both data pointers are pointing to the same place. -Why is this a problem? Well, when `s2` goes out of scope, it will free the -memory that the pointer points to. And then `s1` goes out of scope, and it will -_also_ try to free the memory that the pointer points to! That’s bad. +There’s a problem here! Both data pointers are pointing to the same place. Why +is this a problem? Well, when `s2` goes out of scope, it will free the memory +that the pointer points to. And then `s1` goes out of scope, and it will _also_ +try to free the memory that the pointer points to! That’s bad, and is known as +a "double free" error. So what’s the solution? Here, we stand at a crossroads with a few options. One would be to declare that assignment will also copy out any data. This works, @@ -227,7 +228,7 @@ println!("{}", s1); You’ll get an error like this: -```text +```bash 5:22 error: use of moved value: `s1` [E0382] println!("{}", s1); ^~ @@ -238,7 +239,8 @@ println!("{}", s1); ``` We say that `s1` was _moved_ into `s2`. When a value moves, its data is copied, -but the original variable binding is no longer usable. That solves our problem: +but the original variable binding is no longer usable. That solves our problem, +so what actually happens looks like this: s1 and s2 to the same place @@ -249,17 +251,17 @@ we’re done! This leads us to the Ownership Rules: -> 1. Each value in Rust has a variable binding that’s called it’s ‘owner’. +> 1. Each value in Rust has a variable binding that’s called its ‘owner’. > 2. There can only be one owner at a time. > 3. When the owner goes out of scope, the value will be `drop()`ped. Furthermore, there’s a design choice that’s implied by this: Rust will never -automatically create ‘deep’ copies of your data. Any automatic copying must be -inexpensive. +automatically create ‘deep’ copies of your data. Therefore, any _automatic_ +copying can be assumed to be inexpensive. ## Clone -But what if we _do_ want to deeply copy the `String`’s data, and not just the +But what if we _do_ want to deeply copy the `String`’s data and not just the `String` itself? There’s a common method for that: `clone()`. We will discuss methods in the next section on [`struct`]s, but they’re a common enough feature in many programming languages that you have probably seen them before. @@ -281,7 +283,7 @@ it _is_ doing this: s1 and s2 to two places When you see a call to `clone()`, you know that some arbitrary code is being -executed, which may be expensive. It’s a visual indicator that something +executed, and that code may be expensive. It’s a visual indicator that something different is going on here. ## Copy @@ -297,19 +299,21 @@ println!("{}", x); But why? We don’t have a call to `clone()`. Why didn’t `x` get moved into `y`? -For types that do not have any kind of complex storage requirements, like -integers, typing `clone()` is busy work. There’s no reason we would ever want -to prevent `x` from being valid here, as there’s no situation in which it’s -incorrect. In other words, there’s no difference between deep and shallow -copying here, so calling `clone()` wouldn’t do anything differently from the -usual shallow copying. +Types like integers that have a known size at compile time do not ask for +memory from the operating system and therefore do not need to be `drop()`ped +when they go out of scope. That means there's no reason we would want to +prevent `x` from being valid after we create the binding `y`. In other words, +there’s no difference between deep and shallow copying here, so calling +`clone()` wouldn’t do anything differently from the usual shallow copying and +we can leave it out. -Rust has a special annotation that you can place on types, called `Copy`. If -a type is `Copy`, an older binding is still usable after assignment. Integers -are an example of such a type; most of the primitive types are `Copy`. +Rust has a special annotation that you can place on types like these, and that +annotation is called `Copy`. If a type is `Copy`, an older binding is still +usable after assignment. Integers are an example of such a type; most of the +primitive types are `Copy`. While we haven’t talked about how to mark a type as `Copy` yet, you might ask -yourself “what happens if we made `String` `Copy`?” The answer is, you cannot. +yourself “what happens if we made `String` `Copy`?” The answer is you cannot. Remember `drop()`? Rust will not let you make something `Copy` if it has implemented `drop()`. If you need to do something special when the value goes out of scope, being `Copy` will be an error. @@ -317,8 +321,8 @@ out of scope, being `Copy` will be an error. So what types are `Copy`? You can check the documentation for the given type to be sure, but as a rule of thumb, any group of simple scalar values can be Copy, but nothing that requires allocation or is some form of resource is `Copy`. And -you can’t get it wrong: the compiler will throw an error if you try to use a -type that moves incorrectly, as we saw above. +you can’t get it wrong: the compiler will throw an error if you incorrectly try +to use a type that moves, as we saw above. Here’s some types that you’ve seen so far that are `Copy`: @@ -383,6 +387,8 @@ fn makes_copy(some_integer: i32) { // some_integer comes into scope. Remember: If we tried to use `s` after the call to `takes_ownership()`, Rust would throw a compile-time error! These static checks protect us from mistakes. +Try adding code to `main` that uses `s` and `x` to see where you can use them +and where the ownership rules prevent you from doing so. Returning values can also transfer ownership: @@ -443,9 +449,9 @@ fn takes_and_gives_back(a_string: String) -> String { // a_string comes into sco It’s the same pattern, every time: assigning something moves it, and when an owner goes out of scope, if it hasn’t been moved, it will `drop()`. -This might seem a bit tedious, and it is. What if I want to let a function use -a value, but not take ownership? It’s quite annoying that anything I pass in -also needs passed back. Look at this function: +This might seem a bit tedious, and it is. What if we want to let a function use +a value but not take ownership? It’s quite annoying that anything we pass in +also needs to be passed back if we want to use it again. Like in this function: ```rust fn main() { @@ -466,5 +472,5 @@ fn calculate_length(s: String) -> (String, usize) { This is too much ceremony: we have to use a tuple to give back the `String` as well as the length. It’s a lot of work for a pattern that should be common. -Luckily for us, Rust has such a feature, and it’s what the next section is -about. +Luckily for us, Rust has a feature for this pattern, and it’s what the next +section is about. From 331e24b03fbdf70e5fb97a95b4add35c8b042fad Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 14 Jul 2016 16:30:07 -0400 Subject: [PATCH 070/204] Reference corrections --- src/ch04-02-ownership.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index d176da7afd..0ff71d3407 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -263,7 +263,7 @@ copying can be assumed to be inexpensive. But what if we _do_ want to deeply copy the `String`’s data and not just the `String` itself? There’s a common method for that: `clone()`. We will discuss -methods in the next section on [`struct`]s, but they’re a common enough feature +methods in the section on `struct`s, but they’re a common enough feature in many programming languages that you have probably seen them before. Here’s an example of the `clone()` method in action: @@ -275,8 +275,6 @@ let s2 = s1.clone(); println!("{}", s1); ``` -[`struct`]: structs.html - This will work just fine. Remember our diagram from before? In this case, it _is_ doing this: @@ -324,7 +322,7 @@ but nothing that requires allocation or is some form of resource is `Copy`. And you can’t get it wrong: the compiler will throw an error if you incorrectly try to use a type that moves, as we saw above. -Here’s some types that you’ve seen so far that are `Copy`: +Here’s some types that are `Copy`: * All of the integer types, like `u32`. * The booleans, `true` and `false`. From 5fb35bac81a37a8a1ede54fc9db06a0610748d56 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 14 Jul 2016 18:12:08 -0400 Subject: [PATCH 071/204] Finish the sentence with some help from steve --- src/ch04-02-ownership.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index 0ff71d3407..c487660ef2 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -205,12 +205,12 @@ but is inefficient: what if our `String` contained a novel? Also, it only works for memory. What if, instead of a `String`, we had a `TcpConnection`? Opening and closing a network connection is very similar to allocating and freeing memory, so it would be nice to be able to use the same mechanism, but we can't -because . The solution that we could use there is to -allow the programmer to hook into the assignment, similar to `drop()`, and -write code to fix things up. That would work, but now, an `=` can run arbitrary -code. That’s also not good, and it doesn’t solve our efficiency concerns either. +because creating a new connection requires more than just copying memory: we +have to request a new connection from the operating system. The solution that +we could use there is to allow the programmer to hook into the assignment, +similar to `drop()`, and write code to fix things up. That would work, but now, +an `=` can run arbitrary code. That’s also not good, and it doesn’t solve our +efficiency concerns either. Let’s take a step back: the root of the problem is that `s1` and `s2` both think that they have control of the memory and therefore need to free it. From 0d71ea901e9c2665f4881736da7bc960021692bd Mon Sep 17 00:00:00 2001 From: antmak Date: Fri, 15 Jul 2016 12:38:31 +0700 Subject: [PATCH 072/204] Fix typo --- src/ch03-03-functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch03-03-functions.md b/src/ch03-03-functions.md index 0b279896ae..6992cc41a8 100644 --- a/src/ch03-03-functions.md +++ b/src/ch03-03-functions.md @@ -19,7 +19,7 @@ fn another_function() { Rust code uses `snake_case` as a style for function names: all lower case, with underscores separating words. (It also uses them for variable names, too.) We -can can call any function we’ve defined by using its name and some parentheses: +can call any function we’ve defined by using its name and some parentheses: ```rust fn main() { From 23d44350737beaaa89c85515fcb652f137fae87e Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 14 Jul 2016 18:22:19 -0400 Subject: [PATCH 073/204] Move this comment to the first time we use `push_str()` --- src/ch04-02-ownership.md | 2 +- src/ch04-03-references-and-borrowing.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index c487660ef2..e4103572d6 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -77,7 +77,7 @@ This kind of string can be mutated: ```rust let mut s = String::from("hello"); -s.push_str(", world!"); +s.push_str(", world!"); // push_str() appends a literal to a String println!("{}", s); // This will print `hello, world!` ``` diff --git a/src/ch04-03-references-and-borrowing.md b/src/ch04-03-references-and-borrowing.md index 113215534b..4f2c819e2a 100644 --- a/src/ch04-03-references-and-borrowing.md +++ b/src/ch04-03-references-and-borrowing.md @@ -100,7 +100,7 @@ fn main() { } fn change(some_string: &String) { - some_string.push_str(", world"); // push_str() appends a literal to a String + some_string.push_str(", world"); } ``` @@ -108,7 +108,7 @@ Here’s the error: ```text 8:16 error: cannot borrow immutable borrowed content `*some_string` as mutable - some_string.push_str(", world"); // push_str() appends a literal to a String + some_string.push_str(", world"); ^~~~~~~~~~~ ``` @@ -127,7 +127,7 @@ fn main() { } fn change(some_string: &mut String) { - some_string.push_str(", world"); // push_str() appends a literal to a String + some_string.push_str(", world"); } ``` From c2c744b4a57ee8039e25be12380ec341549391f6 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 14 Jul 2016 18:23:39 -0400 Subject: [PATCH 074/204] 'from' and 'to' are problematic with references, try to avoid :-/ I would actually say "reference to s1" here, but I think this is trying to say "create a reference out of s1" but that sounds like you don't have s1 anymore since you turned it into something else and urgh am I overthinking this? --- src/ch04-03-references-and-borrowing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch04-03-references-and-borrowing.md b/src/ch04-03-references-and-borrowing.md index 4f2c819e2a..3e416ddd85 100644 --- a/src/ch04-03-references-and-borrowing.md +++ b/src/ch04-03-references-and-borrowing.md @@ -62,8 +62,8 @@ let s1 = String::from("hello"); let len = calculate_length(&s1); ``` -The `&s1` syntax lets us create a reference from `s1`. This reference _refers_ -to the value of `s1`, but does not own it. Because it does not own it, the +The `&s1` syntax lets us create a reference with `s1`. This reference _refers_ +to the value of `s1` but does not own it. Because it does not own it, the value it points to will not be dropped when the reference goes out of scope. Likewise, the signature of the function uses `&` to indicate that it takes From 50e477381f66a8d9c3556a61bf3567c7d8af594d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 14 Jul 2016 18:26:27 -0400 Subject: [PATCH 075/204] Wording, spelling, whitespace, and punctuation corrections --- src/ch04-03-references-and-borrowing.md | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/ch04-03-references-and-borrowing.md b/src/ch04-03-references-and-borrowing.md index 3e416ddd85..5b017a3333 100644 --- a/src/ch04-03-references-and-borrowing.md +++ b/src/ch04-03-references-and-borrowing.md @@ -20,7 +20,8 @@ fn calculate_length(s: String) -> (String, usize) { ``` The issue here is that we have to return the `String` back to the calling -function so that it could still use it. +function so that we can still use it there, since it was moved when we called +`calculate_length()`. There is a better way. It looks like this: @@ -40,11 +41,12 @@ fn calculate_length(s: &String) -> usize { } ``` -First, you’ll notice all of the tuple stuff is gone. Next, that we pass `&s1` -into `calculate_lengths()`. And in its definition, we take `&String` rather -than `String`. +First, you’ll notice all of the tuple stuff in the binding declaration and the +function return value is gone. Next, note that we pass `&s1` into +`calculate_length()`, and in its definition, we take `&String` rather than +`String`. -These `&s` are called ‘references’, and they allow you to refer to some value +These `&`s are called ‘references’, and they allow you to refer to some value without taking ownership of it. Here’s a diagram: DIAGRAM GOES HERE of a &String pointing at a String, with (ptr, len, capacity) @@ -67,9 +69,7 @@ to the value of `s1` but does not own it. Because it does not own it, the value it points to will not be dropped when the reference goes out of scope. Likewise, the signature of the function uses `&` to indicate that it takes -a reference as an argument: - -Let’s add some explanatory annotations: +a reference as an argument. Let’s add some explanatory annotations: ```rust fn calculate_length(s: &String) -> usize { // s is a reference to a String @@ -90,7 +90,7 @@ with real life, if I own something, you can borrow it from me. When you’re don you have to give it back. Speaking of which, what if you try to modify something you borrow from me? Try -this code out. Spoiler alert: it doesn’t work: +this code out. Spoiler alert: it doesn’t work! ```rust,ignore fn main() { @@ -106,7 +106,7 @@ fn change(some_string: &String) { Here’s the error: -```text +```bash 8:16 error: cannot borrow immutable borrowed content `*some_string` as mutable some_string.push_str(", world"); ^~~~~~~~~~~ @@ -131,7 +131,7 @@ fn change(some_string: &mut String) { } ``` -First, we had to change `s` to be `mut`. Then, we had to create a mutable +First, we had to change `s` to be `mut`. Then we had to create a mutable reference with `&mut s` and accept a mutable reference with `some_string: &mut String`. @@ -146,7 +146,7 @@ let r2 = &mut s; Here’s the error: -```text +```bash 5:20 error: cannot borrow `s` as mutable more than once at a time [E0499] let r2 = &mut s; ^ @@ -162,13 +162,13 @@ fn main() { ^ ``` -The error is what it says on the tin: you cannot borrow something more than -once at a time in a mutable fashion. This restriction allows for mutation, but -in a very controlled fashion. It is something that new Rustaceans struggle -with, because most languages let you mutate whenever you’d like. +The error is what it says: you cannot borrow something mutably more than once +at a time. This restriction allows for mutation but in a very controlled +fashion. It is something that new Rustaceans struggle with, because most +languages let you mutate whenever you’d like. As always, we can use `{}`s to create a new scope, allowing for multiple mutable -references. Just not _simultaneous_ ones: +references, just not _simultaneous_ ones: ```rust let mut s = String::from("hello"); @@ -181,8 +181,8 @@ let mut s = String::from("hello"); let r2 = &mut s; ``` -There is a similar rule for combining the two kinds of references. This code -errors: +There is a similar rule for combining mutable and immutable references. This +code errors: ```rust,ignore let mut s = String::from("hello"); @@ -245,7 +245,7 @@ fn dangle() -> &String { ^~~~~~~ help: this function’s return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider giving it a ‘static lifetime +help: consider giving it a 'static lifetime ``` This error message refers to a feature we haven’t learned about yet, From ad4a6b6891ae095f6a4afe49d32e40270c640538 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 15 Jul 2016 12:31:45 -0400 Subject: [PATCH 076/204] Replace teaser of more examples with segue to slices --- src/ch04-03-references-and-borrowing.md | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/ch04-03-references-and-borrowing.md b/src/ch04-03-references-and-borrowing.md index 5b017a3333..c1e097abc4 100644 --- a/src/ch04-03-references-and-borrowing.md +++ b/src/ch04-03-references-and-borrowing.md @@ -295,21 +295,4 @@ Here’s a recap of what we’ve talked about: 2. Any number of immutable references . 2. References must always be valid. -While these rules are not complicated on their own, they can be tricky when -applied to real code. Let’s work through a number of examples to help build -our understanding. - -## More Examples - -COMING SOON - - - - - - - - - - - +Next, let's look at a different kind of reference: slices. From 29943118d0f03f71dc0b78e1c003c4023945be92 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 15 Jul 2016 13:33:15 -0400 Subject: [PATCH 077/204] f with corrections --- src/ch04-04-slices.md | 48 +++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/ch04-04-slices.md b/src/ch04-04-slices.md index 3d028635d6..64951aa9b4 100644 --- a/src/ch04-04-slices.md +++ b/src/ch04-04-slices.md @@ -1,11 +1,11 @@ # Slices So far, we’ve talked about types that have ownership, like `String`, and ones -that don’t, like `&String`. There is a second kind of type which does not have +that don’t, like `&String`. There is another kind of type which does not have ownership: slices. Slices let you reference a contiguous sequence of elements -in a collection, rather than the whole collection itself. +in a collection rather than the whole collection itself. -Here’s a small programming problem: write a function which takes a string, +Here’s a small programming problem: write a function which takes a string and returns the first word you find. If we don’t find a space in the string, then the whole string is a word, so the whole thing should be returned. @@ -39,9 +39,9 @@ Let’s break that down a bit: ```rust fn first_word(s: &String) -> usize { - // Since we need to go through the String element by element, and + // Since we need to go through the String element by element and // check if a value is a space, we will convert our String to an - // array of bytes, using the `.as_bytes()` method. + // array of bytes using the `.as_bytes()` method. let bytes = s.as_bytes(); // We discussed using the iter() method with for in Chapter 3.7. Here, @@ -52,26 +52,25 @@ fn first_word(s: &String) -> usize { // nicer than calculating the index ourselves. // // Since it’s a tuple, we can use patterns, just like elsewhere in Rust. - // So we match against the tuple with i for the index, and &byte for + // So we match against the tuple with i for the index and &byte for // the byte itself. for (i, &byte) in bytes.iter().enumerate() { // 32 is the value of a space in UTF-8 if byte == 32 { - // We found a space! Return this position. return i; } } - // If we got here, we didn’t find a space, so this whole thing must be a - // word. So return the length. + // If we got here, we didn’t find a space, so the whole string must be a + // word. Return the length. s.len() } ``` This works, but there’s a problem. We’re returning a `usize` on its own, but -it’s only a meaningful number in the context of the `&String` itself. In other +it’s only a meaningful number in the context of the `&String`. In other words, because it’s a separate value from the `String`, there’s no guarantee that it will still be valid in the future. Consider this: @@ -91,11 +90,12 @@ that it will still be valid in the future. Consider this: fn main() { let mut s = String::from("hello world"); - let word = first_word(&s); + let word = first_word(&s); // word will get the value 5. s.clear(); // This empties the String, making it equal to "". - // word is now totally invalid! There’s no more word here. + // word still has the value 5 here, but there's no more string that + // we could meaningfully use the value 5 with. word is now totally invalid! } ``` @@ -106,7 +106,7 @@ function. Its signature would have to look like this: fn second_word(s: &String) -> (usize, usize) { ``` -Now we’re tracking both a start _and_ and ending index. Even more chances for +Now we’re tracking both a start _and_ an ending index. Even more chances for things to go wrong. We now have three unrelated variable bindings floating around which need to be kept in sync. @@ -136,8 +136,8 @@ characters. The offset to the first byte of a `String` is 0 and the trailing number should point to the first byte that is _not_ included in the slice. -With Rust’s `..` syntax, if you want to start at zero, you can drop the zero. -In other words, these are equal: +With Rust’s `..` range syntax, if you want to start at the first index (zero), +you can drop the value before the `..`. In other words, these are equal: ```rust let s = String::from("hello"); @@ -147,7 +147,7 @@ let slice = &s[..2]; ``` By the same token, if your slice should include the last byte of the -`String`, you can drop the trailing number. In other words, these are +`String`, you can drop the trailing number. That means these are equal: ```rust @@ -155,8 +155,20 @@ let s = String::from("hello"); let len = s.len(); +let slice = &s[3..len]; +let slice = &s[3..]; +``` + +You can also drop both values to take a slice of the entire string. So these +are equal: + +```rust +let s = String::from("hello"); + +let len = s.len(); + let slice = &s[0..len]; -let slice = &s[0..]; +let slice = &s[..]; ``` With this in mind, let’s re-write `first_word()` to return a slice: @@ -183,7 +195,7 @@ This would also work for a `second_word()`: fn second_word(s: &String) -> &str { ``` -Same deal. We now have a straightforward API, that’s much harder to mess up. +Same deal. We now have a straightforward API that’s much harder to mess up. But what about our error condition from before? Slices also fix that. Using the slice version of `first_word()` will throw an error: From 0c9c7637e8305c50fa52326f0a48b8665f542e5e Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 15 Jul 2016 14:04:10 -0400 Subject: [PATCH 078/204] Fix forward/backward references --- src/ch04-04-slices.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ch04-04-slices.md b/src/ch04-04-slices.md index 64951aa9b4..2107287968 100644 --- a/src/ch04-04-slices.md +++ b/src/ch04-04-slices.md @@ -44,10 +44,10 @@ fn first_word(s: &String) -> usize { // array of bytes using the `.as_bytes()` method. let bytes = s.as_bytes(); - // We discussed using the iter() method with for in Chapter 3.7. Here, - // we’re adding another method: enumerate(). While iter() returns each - // element, enumerate() modifies the result of iter(), and returns a - // tuple instead. The first element of the tuple is the index, and the + // We will be discussing iterators in more detail in Chapter XX, but for + // now, know that `iter()` is a method that returns each element in a + // collection, and `enumerate()` modifies the result of `iter()` and returns + // a tuple instead. The first element of the tuple is the index, and the // second element is a reference to the element itself. This is a bit // nicer than calculating the index ourselves. // @@ -322,6 +322,6 @@ let slice = &a[1..3]; ``` This slice has the type `&[i32]`. It works the exact same way as string slices -do, with a reference to the first element, and a length. You’ll use this kind -of slice for all sorts of other collections. We’ll discuss these other slices -in detail when we talk about vectors, in Chapter 9.1. +do, by storing a reference to the first element and a length. You’ll use this +kind of slice for all sorts of other collections. We’ll discuss these in detail +when we talk about vectors in Chapter XX. From f5e49624d83ea2f94482743a82203fd232291e76 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 15 Jul 2016 14:04:29 -0400 Subject: [PATCH 079/204] Hopefully clarify string slice syntax vs internal representation Fixes #107. --- src/ch04-04-slices.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/ch04-04-slices.md b/src/ch04-04-slices.md index 2107287968..af466fe9e9 100644 --- a/src/ch04-04-slices.md +++ b/src/ch04-04-slices.md @@ -124,17 +124,18 @@ let world = &s[6..11]; ``` This looks just like taking a reference to the whole `String`, but with the -extra `[0..5]` bit. Instead of being a reference to the entire `String`, -it’s a reference to an internal position in the `String`, but it also keeps -track of the number of elements that it refers to as well. In other words, -it looks like this: +extra `[0..5]` bit. Instead of being a reference to the entire `String`, it’s a +reference to an internal position in the `String` and the number of elements +that it refers to. -DIAGRAM GOES HERE of s, hello, and world +We can create slices with a range of `[starting_index..ending_index]`, but the +slice data structure actually stores the starting position and the length of the +slice. So in the case of `let world = &s[6..11];`, `world` would be a slice that +contains a pointer to the 6th byte of `s` and a length value of 5. + +In other words, it looks like this: -Note that the internal position is specified through byte-offsets, not -characters. The offset to the first byte of a `String` is 0 and the -trailing number should point to the first byte that is _not_ included -in the slice. +DIAGRAM GOES HERE of s, hello, and world With Rust’s `..` range syntax, if you want to start at the first index (zero), you can drop the value before the `..`. In other words, these are equal: @@ -187,8 +188,10 @@ fn first_word(s: &String) -> &str { } ``` -Now, we have a single value, the `&str`. It contains both elements that we care -about: a reference to the starting point, and the number of elements. +Now we have a single value, the `&str`, pronounced "string slice". It stores +both elements that we care about: a reference to the starting point of the +slice and the number of elements in the slice. + This would also work for a `second_word()`: ```rust,ignore From ec7485575d7ca36977bf4c48bd8de0c6b8969083 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 19:30:52 -0400 Subject: [PATCH 080/204] 3 is 4. 4 is 3. War is peace. Freedom is slavery. Ignorance is strength. --- src/SUMMARY.md | 16 ++++++++++++---- ...hip.md => ch03-01-understanding-ownership.md} | 0 ...ch04-02-ownership.md => ch03-02-ownership.md} | 0 ...ng.md => ch03-03-references-and-borrowing.md} | 0 src/{ch04-04-slices.md => ch03-04-slices.md} | 0 ...-and-running.md => ch04-01-up-and-running.md} | 0 ...m.md => ch04-02-anatomy-of-a-rust-program.md} | 0 ...md => ch04-03-variable-bindings-in-detail.md} | 0 ...-in-rust.md => ch04-04-data-types-in-rust.md} | 0 ...-in-rust.md => ch04-05-how-functions-work.md} | 0 src/{ch03-06-comments.md => ch04-06-comments.md} | 0 ...7-control-flow.md => ch04-07-control-flow.md} | 0 12 files changed, 12 insertions(+), 4 deletions(-) rename src/{ch04-01-understanding-ownership.md => ch03-01-understanding-ownership.md} (100%) rename src/{ch04-02-ownership.md => ch03-02-ownership.md} (100%) rename src/{ch04-03-references-and-borrowing.md => ch03-03-references-and-borrowing.md} (100%) rename src/{ch04-04-slices.md => ch03-04-slices.md} (100%) rename src/{ch03-01-up-and-running.md => ch04-01-up-and-running.md} (100%) rename src/{ch03-02-anatomy-of-a-rust-program.md => ch04-02-anatomy-of-a-rust-program.md} (100%) rename src/{ch03-03-variable-bindings-in-detail.md => ch04-03-variable-bindings-in-detail.md} (100%) rename src/{ch03-04-data-types-in-rust.md => ch04-04-data-types-in-rust.md} (100%) rename src/{ch03-05-how-functions-work-in-rust.md => ch04-05-how-functions-work.md} (100%) rename src/{ch03-06-comments.md => ch04-06-comments.md} (100%) rename src/{ch03-07-control-flow.md => ch04-07-control-flow.md} (100%) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 945102e598..79a9a23243 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -7,10 +7,18 @@ - [Guessing Game Tutorial](ch02-01-guessing-game-tutorial.md) -- [Understanding Ownership](ch04-01-understanding-ownership.md) - - [Ownership](ch04-02-ownership.md) - - [References & Borrowing](ch04-03-references-and-borrowing.md) - - [Slices](ch04-04-slices.md) +- [Understanding Ownership](ch03-01-understanding-ownership.md) + - [Ownership](ch03-02-ownership.md) + - [References & Borrowing](ch03-03-references-and-borrowing.md) + - [Slices](ch03-04-slices.md) + +- [Up and Running](ch04-01-up-and-running.md) + - [Anatomy of a Rust Program](ch04-02-anatomy-of-a-rust-program.md) + - [Variable Bindings in Detail](ch04-03-variable-bindings-in-detail.md) + - [Data Types in Rust](ch04-04-data-types-in-rust.md) + - [How Functions Work](ch04-05-how-functions-work.md) + - [Comments](ch04-06-comments.md) + - [Control Flow](ch04-07-control-flow.md) - [Structs](ch05-01-structs.md) - [Method Syntax](ch05-02-method-syntax.md) diff --git a/src/ch04-01-understanding-ownership.md b/src/ch03-01-understanding-ownership.md similarity index 100% rename from src/ch04-01-understanding-ownership.md rename to src/ch03-01-understanding-ownership.md diff --git a/src/ch04-02-ownership.md b/src/ch03-02-ownership.md similarity index 100% rename from src/ch04-02-ownership.md rename to src/ch03-02-ownership.md diff --git a/src/ch04-03-references-and-borrowing.md b/src/ch03-03-references-and-borrowing.md similarity index 100% rename from src/ch04-03-references-and-borrowing.md rename to src/ch03-03-references-and-borrowing.md diff --git a/src/ch04-04-slices.md b/src/ch03-04-slices.md similarity index 100% rename from src/ch04-04-slices.md rename to src/ch03-04-slices.md diff --git a/src/ch03-01-up-and-running.md b/src/ch04-01-up-and-running.md similarity index 100% rename from src/ch03-01-up-and-running.md rename to src/ch04-01-up-and-running.md diff --git a/src/ch03-02-anatomy-of-a-rust-program.md b/src/ch04-02-anatomy-of-a-rust-program.md similarity index 100% rename from src/ch03-02-anatomy-of-a-rust-program.md rename to src/ch04-02-anatomy-of-a-rust-program.md diff --git a/src/ch03-03-variable-bindings-in-detail.md b/src/ch04-03-variable-bindings-in-detail.md similarity index 100% rename from src/ch03-03-variable-bindings-in-detail.md rename to src/ch04-03-variable-bindings-in-detail.md diff --git a/src/ch03-04-data-types-in-rust.md b/src/ch04-04-data-types-in-rust.md similarity index 100% rename from src/ch03-04-data-types-in-rust.md rename to src/ch04-04-data-types-in-rust.md diff --git a/src/ch03-05-how-functions-work-in-rust.md b/src/ch04-05-how-functions-work.md similarity index 100% rename from src/ch03-05-how-functions-work-in-rust.md rename to src/ch04-05-how-functions-work.md diff --git a/src/ch03-06-comments.md b/src/ch04-06-comments.md similarity index 100% rename from src/ch03-06-comments.md rename to src/ch04-06-comments.md diff --git a/src/ch03-07-control-flow.md b/src/ch04-07-control-flow.md similarity index 100% rename from src/ch03-07-control-flow.md rename to src/ch04-07-control-flow.md From 3a90e160d731f388a76bb2c5008ed83a2877d8e1 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 19:34:05 -0400 Subject: [PATCH 081/204] Remove placeholders --- src/SUMMARY.md | 2 -- src/ch01-04-design.md | 1 - 2 files changed, 3 deletions(-) delete mode 100644 src/ch01-04-design.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 79a9a23243..7ac09a34fe 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -3,7 +3,6 @@ - [Introduction](ch01-01-introduction.md) - [Installation](ch01-02-installation.md) - [Hello, World!](ch01-03-hello-world.md) - - [The Design of Rust](ch01-04-design.md) - [Guessing Game Tutorial](ch02-01-guessing-game-tutorial.md) @@ -23,7 +22,6 @@ - [Structs](ch05-01-structs.md) - [Method Syntax](ch05-02-method-syntax.md) - [Generics](ch05-03-generics.md) - - [Advanced]() - [Enums](ch06-01-enums.md) - [Option](ch06-02-option.md) diff --git a/src/ch01-04-design.md b/src/ch01-04-design.md deleted file mode 100644 index 139ee1fa19..0000000000 --- a/src/ch01-04-design.md +++ /dev/null @@ -1 +0,0 @@ -# The Design of Rust From 432891268613d6385bb38c4d5f7357ade697619d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 19:42:44 -0400 Subject: [PATCH 082/204] Rename files to better match mdbook generated sidebar numbering I have had off-by-one errors when I'm talking to people and looking at the file names, but they're looking at the sidebar in the generated output, since the first section in a chapter doesn't get a number in the sidebar, and the second section in a chapter gets named x.1, etc. Just wait til I try to name cache invalidation. --- src/SUMMARY.md | 46 +++++++++---------- ...ntroduction.md => ch01-00-introduction.md} | 0 ...nstallation.md => ch01-01-installation.md} | 0 ...-hello-world.md => ch01-02-hello-world.md} | 0 ...l.md => ch02-00-guessing-game-tutorial.md} | 0 ....md => ch03-00-understanding-ownership.md} | 0 ...3-02-ownership.md => ch03-01-ownership.md} | 0 ...md => ch03-02-references-and-borrowing.md} | 0 src/{ch03-04-slices.md => ch03-03-slices.md} | 0 ...d-running.md => ch04-00-up-and-running.md} | 0 ...d => ch04-01-anatomy-of-a-rust-program.md} | 0 ...=> ch04-02-variable-bindings-in-detail.md} | 0 ...-rust.md => ch04-03-data-types-in-rust.md} | 0 ...-work.md => ch04-04-how-functions-work.md} | 0 ...h04-06-comments.md => ch04-05-comments.md} | 0 ...ontrol-flow.md => ch04-06-control-flow.md} | 0 ...{ch05-01-structs.md => ch05-00-structs.md} | 0 ...hod-syntax.md => ch05-01-method-syntax.md} | 0 ...h05-03-generics.md => ch05-02-generics.md} | 0 src/{ch06-01-enums.md => ch06-00-enums.md} | 0 src/{ch06-02-option.md => ch06-01-option.md} | 0 src/{ch06-03-match.md => ch06-02-match.md} | 0 ...h06-04-patterns.md => ch06-03-patterns.md} | 0 src/{ch06-05-if-let.md => ch06-04-if-let.md} | 0 24 files changed, 23 insertions(+), 23 deletions(-) rename src/{ch01-01-introduction.md => ch01-00-introduction.md} (100%) rename src/{ch01-02-installation.md => ch01-01-installation.md} (100%) rename src/{ch01-03-hello-world.md => ch01-02-hello-world.md} (100%) rename src/{ch02-01-guessing-game-tutorial.md => ch02-00-guessing-game-tutorial.md} (100%) rename src/{ch03-01-understanding-ownership.md => ch03-00-understanding-ownership.md} (100%) rename src/{ch03-02-ownership.md => ch03-01-ownership.md} (100%) rename src/{ch03-03-references-and-borrowing.md => ch03-02-references-and-borrowing.md} (100%) rename src/{ch03-04-slices.md => ch03-03-slices.md} (100%) rename src/{ch04-01-up-and-running.md => ch04-00-up-and-running.md} (100%) rename src/{ch04-02-anatomy-of-a-rust-program.md => ch04-01-anatomy-of-a-rust-program.md} (100%) rename src/{ch04-03-variable-bindings-in-detail.md => ch04-02-variable-bindings-in-detail.md} (100%) rename src/{ch04-04-data-types-in-rust.md => ch04-03-data-types-in-rust.md} (100%) rename src/{ch04-05-how-functions-work.md => ch04-04-how-functions-work.md} (100%) rename src/{ch04-06-comments.md => ch04-05-comments.md} (100%) rename src/{ch04-07-control-flow.md => ch04-06-control-flow.md} (100%) rename src/{ch05-01-structs.md => ch05-00-structs.md} (100%) rename src/{ch05-02-method-syntax.md => ch05-01-method-syntax.md} (100%) rename src/{ch05-03-generics.md => ch05-02-generics.md} (100%) rename src/{ch06-01-enums.md => ch06-00-enums.md} (100%) rename src/{ch06-02-option.md => ch06-01-option.md} (100%) rename src/{ch06-03-match.md => ch06-02-match.md} (100%) rename src/{ch06-04-patterns.md => ch06-03-patterns.md} (100%) rename src/{ch06-05-if-let.md => ch06-04-if-let.md} (100%) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 7ac09a34fe..47dcbdd508 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -1,30 +1,30 @@ # The Rust Programming Language -- [Introduction](ch01-01-introduction.md) - - [Installation](ch01-02-installation.md) - - [Hello, World!](ch01-03-hello-world.md) +- [Introduction](ch01-00-introduction.md) + - [Installation](ch01-01-installation.md) + - [Hello, World!](ch01-02-hello-world.md) -- [Guessing Game Tutorial](ch02-01-guessing-game-tutorial.md) +- [Guessing Game Tutorial](ch02-00-guessing-game-tutorial.md) -- [Understanding Ownership](ch03-01-understanding-ownership.md) - - [Ownership](ch03-02-ownership.md) - - [References & Borrowing](ch03-03-references-and-borrowing.md) - - [Slices](ch03-04-slices.md) +- [Understanding Ownership](ch03-00-understanding-ownership.md) + - [Ownership](ch03-01-ownership.md) + - [References & Borrowing](ch03-02-references-and-borrowing.md) + - [Slices](ch03-03-slices.md) -- [Up and Running](ch04-01-up-and-running.md) - - [Anatomy of a Rust Program](ch04-02-anatomy-of-a-rust-program.md) - - [Variable Bindings in Detail](ch04-03-variable-bindings-in-detail.md) - - [Data Types in Rust](ch04-04-data-types-in-rust.md) - - [How Functions Work](ch04-05-how-functions-work.md) - - [Comments](ch04-06-comments.md) - - [Control Flow](ch04-07-control-flow.md) +- [Up and Running](ch04-00-up-and-running.md) + - [Anatomy of a Rust Program](ch04-01-anatomy-of-a-rust-program.md) + - [Variable Bindings in Detail](ch04-02-variable-bindings-in-detail.md) + - [Data Types in Rust](ch04-03-data-types-in-rust.md) + - [How Functions Work](ch04-04-how-functions-work.md) + - [Comments](ch04-05-comments.md) + - [Control Flow](ch04-06-control-flow.md) -- [Structs](ch05-01-structs.md) - - [Method Syntax](ch05-02-method-syntax.md) - - [Generics](ch05-03-generics.md) +- [Structs](ch05-00-structs.md) + - [Method Syntax](ch05-01-method-syntax.md) + - [Generics](ch05-02-generics.md) -- [Enums](ch06-01-enums.md) - - [Option](ch06-02-option.md) - - [Match](ch06-03-match.md) - - [Patterns](ch06-04-patterns.md) - - [if let](ch06-05-if-let.md) +- [Enums](ch06-00-enums.md) + - [Option](ch06-01-option.md) + - [Match](ch06-02-match.md) + - [Patterns](ch06-03-patterns.md) + - [if let](ch06-04-if-let.md) diff --git a/src/ch01-01-introduction.md b/src/ch01-00-introduction.md similarity index 100% rename from src/ch01-01-introduction.md rename to src/ch01-00-introduction.md diff --git a/src/ch01-02-installation.md b/src/ch01-01-installation.md similarity index 100% rename from src/ch01-02-installation.md rename to src/ch01-01-installation.md diff --git a/src/ch01-03-hello-world.md b/src/ch01-02-hello-world.md similarity index 100% rename from src/ch01-03-hello-world.md rename to src/ch01-02-hello-world.md diff --git a/src/ch02-01-guessing-game-tutorial.md b/src/ch02-00-guessing-game-tutorial.md similarity index 100% rename from src/ch02-01-guessing-game-tutorial.md rename to src/ch02-00-guessing-game-tutorial.md diff --git a/src/ch03-01-understanding-ownership.md b/src/ch03-00-understanding-ownership.md similarity index 100% rename from src/ch03-01-understanding-ownership.md rename to src/ch03-00-understanding-ownership.md diff --git a/src/ch03-02-ownership.md b/src/ch03-01-ownership.md similarity index 100% rename from src/ch03-02-ownership.md rename to src/ch03-01-ownership.md diff --git a/src/ch03-03-references-and-borrowing.md b/src/ch03-02-references-and-borrowing.md similarity index 100% rename from src/ch03-03-references-and-borrowing.md rename to src/ch03-02-references-and-borrowing.md diff --git a/src/ch03-04-slices.md b/src/ch03-03-slices.md similarity index 100% rename from src/ch03-04-slices.md rename to src/ch03-03-slices.md diff --git a/src/ch04-01-up-and-running.md b/src/ch04-00-up-and-running.md similarity index 100% rename from src/ch04-01-up-and-running.md rename to src/ch04-00-up-and-running.md diff --git a/src/ch04-02-anatomy-of-a-rust-program.md b/src/ch04-01-anatomy-of-a-rust-program.md similarity index 100% rename from src/ch04-02-anatomy-of-a-rust-program.md rename to src/ch04-01-anatomy-of-a-rust-program.md diff --git a/src/ch04-03-variable-bindings-in-detail.md b/src/ch04-02-variable-bindings-in-detail.md similarity index 100% rename from src/ch04-03-variable-bindings-in-detail.md rename to src/ch04-02-variable-bindings-in-detail.md diff --git a/src/ch04-04-data-types-in-rust.md b/src/ch04-03-data-types-in-rust.md similarity index 100% rename from src/ch04-04-data-types-in-rust.md rename to src/ch04-03-data-types-in-rust.md diff --git a/src/ch04-05-how-functions-work.md b/src/ch04-04-how-functions-work.md similarity index 100% rename from src/ch04-05-how-functions-work.md rename to src/ch04-04-how-functions-work.md diff --git a/src/ch04-06-comments.md b/src/ch04-05-comments.md similarity index 100% rename from src/ch04-06-comments.md rename to src/ch04-05-comments.md diff --git a/src/ch04-07-control-flow.md b/src/ch04-06-control-flow.md similarity index 100% rename from src/ch04-07-control-flow.md rename to src/ch04-06-control-flow.md diff --git a/src/ch05-01-structs.md b/src/ch05-00-structs.md similarity index 100% rename from src/ch05-01-structs.md rename to src/ch05-00-structs.md diff --git a/src/ch05-02-method-syntax.md b/src/ch05-01-method-syntax.md similarity index 100% rename from src/ch05-02-method-syntax.md rename to src/ch05-01-method-syntax.md diff --git a/src/ch05-03-generics.md b/src/ch05-02-generics.md similarity index 100% rename from src/ch05-03-generics.md rename to src/ch05-02-generics.md diff --git a/src/ch06-01-enums.md b/src/ch06-00-enums.md similarity index 100% rename from src/ch06-01-enums.md rename to src/ch06-00-enums.md diff --git a/src/ch06-02-option.md b/src/ch06-01-option.md similarity index 100% rename from src/ch06-02-option.md rename to src/ch06-01-option.md diff --git a/src/ch06-03-match.md b/src/ch06-02-match.md similarity index 100% rename from src/ch06-03-match.md rename to src/ch06-02-match.md diff --git a/src/ch06-04-patterns.md b/src/ch06-03-patterns.md similarity index 100% rename from src/ch06-04-patterns.md rename to src/ch06-03-patterns.md diff --git a/src/ch06-05-if-let.md b/src/ch06-04-if-let.md similarity index 100% rename from src/ch06-05-if-let.md rename to src/ch06-04-if-let.md From bf7971b392f46cc432cfde05d53b81057c2111d4 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 20:19:15 -0400 Subject: [PATCH 083/204] Give ch 4 a better title We've been up and running for a bit, now that we have the tutorial and ownership chapters before this one. --- src/SUMMARY.md | 2 +- ...unning.md => ch04-00-common-programming-concepts-in-rust.md} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/{ch04-00-up-and-running.md => ch04-00-common-programming-concepts-in-rust.md} (93%) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 47dcbdd508..a04db33801 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -11,7 +11,7 @@ - [References & Borrowing](ch03-02-references-and-borrowing.md) - [Slices](ch03-03-slices.md) -- [Up and Running](ch04-00-up-and-running.md) +- [Common Programming Concepts in Rust](ch04-00-common-programming-concepts-in-rust.md) - [Anatomy of a Rust Program](ch04-01-anatomy-of-a-rust-program.md) - [Variable Bindings in Detail](ch04-02-variable-bindings-in-detail.md) - [Data Types in Rust](ch04-03-data-types-in-rust.md) diff --git a/src/ch04-00-up-and-running.md b/src/ch04-00-common-programming-concepts-in-rust.md similarity index 93% rename from src/ch04-00-up-and-running.md rename to src/ch04-00-common-programming-concepts-in-rust.md index 8b1bbba587..51273ecf6e 100644 --- a/src/ch04-00-up-and-running.md +++ b/src/ch04-00-common-programming-concepts-in-rust.md @@ -1,4 +1,4 @@ -# Up and Running +# Common Programming Concepts in Rust We’ll start our Rust journey by talking about the absolute basics, concepts that appear in almost every programming language. Many programming languages From fe717e26d4054fe9d50647d62ad2606ddd8f1b80 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 20:22:06 -0400 Subject: [PATCH 084/204] Rework ch 4 intro given that it's later in the book now Is the first paragraph too repetitive? --- src/ch04-00-common-programming-concepts-in-rust.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ch04-00-common-programming-concepts-in-rust.md b/src/ch04-00-common-programming-concepts-in-rust.md index 51273ecf6e..e4c67f5427 100644 --- a/src/ch04-00-common-programming-concepts-in-rust.md +++ b/src/ch04-00-common-programming-concepts-in-rust.md @@ -1,11 +1,11 @@ # Common Programming Concepts in Rust -We’ll start our Rust journey by talking about the absolute basics, concepts -that appear in almost every programming language. Many programming languages -have much in common at their core. None of the concepts presented in this -chapter are unique to Rust, but we’ll discuss Rust’s particular syntax and -conventions concerning these common concepts. +Now that we've seen some of the features that make Rust unique, let's look at +concepts that appear in almost every programming language and see how they work +in Rust. Many programming languages have much in common at their core. None of +the concepts presented in this chapter are unique to Rust, but we’ll discuss +Rust’s particular syntax and conventions concerning these common concepts. -Specifically, we’ll be talking about variable bindings, functions, basic types, -comments, `if` statements, and looping. These foundations will be in every Rust +Specifically, we’ll be talking about variable bindings, basic types, functions, +comments, and control flow. These foundations will be in every Rust program, and learning them early will give you a strong core to start from. From 892a44cc7e55d84af5904758d1185c3bb6120d4c Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 20:34:52 -0400 Subject: [PATCH 085/204] Move keywords to an appendix --- src/SUMMARY.md | 5 ++ src/appendix-00.md | 4 ++ src/appendix-01-keywords.md | 58 ++++++++++++++++++++++ src/ch04-01-anatomy-of-a-rust-program.md | 63 ++---------------------- 4 files changed, 72 insertions(+), 58 deletions(-) create mode 100644 src/appendix-00.md create mode 100644 src/appendix-01-keywords.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index a04db33801..783f5be82c 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -28,3 +28,8 @@ - [Match](ch06-02-match.md) - [Patterns](ch06-03-patterns.md) - [if let](ch06-04-if-let.md) + +- [MANY MORE CHAPTERS COMING SOON]() + +- [Appendix](appendix-00.md) + - [Keywords](appendix-01-keywords.md) \ No newline at end of file diff --git a/src/appendix-00.md b/src/appendix-00.md new file mode 100644 index 0000000000..83a7e91329 --- /dev/null +++ b/src/appendix-00.md @@ -0,0 +1,4 @@ +# Appendix + +The following sections contain reference material you may find useful in your +Rust journey. diff --git a/src/appendix-01-keywords.md b/src/appendix-01-keywords.md new file mode 100644 index 0000000000..1957f95c91 --- /dev/null +++ b/src/appendix-01-keywords.md @@ -0,0 +1,58 @@ +## Keywords + +The following keywords are reserved by the Rust language and may not be used as +names of functions, variables, macros, modules, crates, constants, static +values, attributes, struct fields, or arguments. + +* `abstract` +* `alignof` +* `as` +* `become` +* `box` +* `break` +* `const` +* `continue` +* `crate` +* `do` +* `else` +* `enum` +* `extern` +* `false` +* `final` +* `fn` +* `for` +* `if` +* `impl` +* `in` +* `let` +* `loop` +* `macro` +* `match` +* `mod` +* `move` +* `mut` +* `offsetof` +* `override` +* `priv` +* `proc` +* `pub` +* `pure` +* `ref` +* `return` +* `Self` +* `self` +* `sizeof` +* `static` +* `struct` +* `super` +* `trait` +* `true` +* `type` +* `typeof` +* `unsafe` +* `unsized` +* `use` +* `virtual` +* `where` +* `while` +* `yield` diff --git a/src/ch04-01-anatomy-of-a-rust-program.md b/src/ch04-01-anatomy-of-a-rust-program.md index f935694aac..29f734a3ef 100644 --- a/src/ch04-01-anatomy-of-a-rust-program.md +++ b/src/ch04-01-anatomy-of-a-rust-program.md @@ -5,69 +5,16 @@ data, but to create this data, you first have to create a program. Here, we'll write some code that demonstrates how to begin a Rust program, how to bind a variable, and how to print text to the terminal. -### Keywords +PROD: START BOX -First, keep in mind that the Rust language has a set of *keywords* that have +Keep in mind that the Rust language has a set of *keywords* that have been reserved for use by the language only. This means you cannot use these words as names of variables or functions, for example. Most of these have special meaning and we will be using them to do various things in our Rust programs; a few have no current functionality associated but have been reserved -for functionality that might be in the Rust language in the future. - -The keywords are: - -* `abstract` -* `alignof` -* `as` -* `become` -* `box` -* `break` -* `const` -* `continue` -* `crate` -* `do` -* `else` -* `enum` -* `extern` -* `false` -* `final` -* `fn` -* `for` -* `if` -* `impl` -* `in` -* `let` -* `loop` -* `macro` -* `match` -* `mod` -* `move` -* `mut` -* `offsetof` -* `override` -* `priv` -* `proc` -* `pub` -* `pure` -* `ref` -* `return` -* `Self` -* `self` -* `sizeof` -* `static` -* `struct` -* `super` -* `trait` -* `true` -* `type` -* `typeof` -* `unsafe` -* `unsized` -* `use` -* `virtual` -* `where` -* `while` -* `yield` +for functionality that might be in the Rust language in the future. You can find a list of the keywords in Appendix XX. + +PROD: END BOX ### A Simple Program that Binds a Variable From f0ab249c3254ba5ad559d747d22d4a6863114174 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 20:37:01 -0400 Subject: [PATCH 086/204] Correct a reference since functions isn't the next section --- src/ch04-01-anatomy-of-a-rust-program.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch04-01-anatomy-of-a-rust-program.md b/src/ch04-01-anatomy-of-a-rust-program.md index 29f734a3ef..0111268d23 100644 --- a/src/ch04-01-anatomy-of-a-rust-program.md +++ b/src/ch04-01-anatomy-of-a-rust-program.md @@ -73,7 +73,7 @@ fn main() { The `main()` function is the entry point of every executable Rust program. It doesn’t have to be at the very beginning of our source code, but it will be the first bit of code that runs when we execute our program. We’ll talk more about -functions in the next section, but for now, just know that `main()` is +functions in a later section, but for now, just know that `main()` is where our program begins. The opening curly brace (`{`) indicates the start of the function’s body. From d1a8fc5e82848815ac6e478e281431ace74e36db Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 20:46:01 -0400 Subject: [PATCH 087/204] Remove some details that aren't essential to know at this point --- src/ch04-01-anatomy-of-a-rust-program.md | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/ch04-01-anatomy-of-a-rust-program.md b/src/ch04-01-anatomy-of-a-rust-program.md index 0111268d23..65f75791be 100644 --- a/src/ch04-01-anatomy-of-a-rust-program.md +++ b/src/ch04-01-anatomy-of-a-rust-program.md @@ -107,19 +107,6 @@ let x = 2 + 3; The expression `2 + 3` would evaluate to `5`, which would in turn be stored in the `x` variable binding. -More generally, `let` statements take the form: - -```text -let PATTERN = EXPRESSION; -``` - -*Patterns* are part of the ‘pattern matching’ feature of Rust. If you have -worked with regular expressions, you can think of patterns like a regular -expression that works on values in your program instead of characters in text. -A name like `x` is a particularly humble form of pattern; it will always match -and gets all the parts of the expression as its value. Patterns are a big part -of Rust, and we’ll see more complex and powerful patterns as we go along. - #### Printing to the Screen with a Macro The next line of our program is: @@ -164,8 +151,7 @@ The value of x is 5, and the value of y is 10 Think of `{}` as little crab pincers, holding a value in place. The first `{}` holds the first value after the format string, the second set holds the second -value, and so on. The `{}` placeholder has a number of more advanced formatting -options that we’ll discuss later. +value, and so on. After the `println!` macro, we match the opening curly brace that declared the `main()` function with a closing curly brace to declare the end of the function: From 1512bba8c4865ed69743af7e1a2be48d4bc84ed3 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 20:46:46 -0400 Subject: [PATCH 088/204] Avoid using phrases like 'of course' --- src/ch04-01-anatomy-of-a-rust-program.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch04-01-anatomy-of-a-rust-program.md b/src/ch04-01-anatomy-of-a-rust-program.md index 65f75791be..6094282b12 100644 --- a/src/ch04-01-anatomy-of-a-rust-program.md +++ b/src/ch04-01-anatomy-of-a-rust-program.md @@ -160,7 +160,7 @@ After the `println!` macro, we match the opening curly brace that declared the } ``` -And of course, when we run the program, our output is: +And as we saw earlier, when we run the program, our output is: ```text The value of x is: 5 From 679475e784d840e590f8bc1d9ce914c1853b625b Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 21:30:58 -0400 Subject: [PATCH 089/204] Cut some more non-essential sections --- src/ch04-02-variable-bindings-in-detail.md | 33 +--------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/src/ch04-02-variable-bindings-in-detail.md b/src/ch04-02-variable-bindings-in-detail.md index 25678fc2fe..9a241cf646 100644 --- a/src/ch04-02-variable-bindings-in-detail.md +++ b/src/ch04-02-variable-bindings-in-detail.md @@ -205,38 +205,7 @@ The value of x is: 5 The value of x is: 6 ``` -Using `mut`, we change the value that `x` binds to from `5` to `6`. Note, -however, that `mut` is part of the pattern in the `let` statement. This becomes -more obvious if we try to add mutability to a pattern that binds multiple -variables in the same way as we did for a single variable, like this: - -```rust,ignore -fn main() { - let (mut x, y) = (5, 6); - x = 7; - y = 8; -} -``` - -If you run this code, the compiler will output an error: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:5:5: 5:10 error: re-assignment of immutable variable `y` [E0384] -src/main.rs:5 y = 8; - ^~~~~ -src/main.rs:5:5: 5:10 help: run `rustc --explain E0384` to see a detailed explanation -src/main.rs:2:17: 2:18 note: prior assignment occurs here -src/main.rs:2 let (mut x, y) = (5, 6); - ^ -``` - -The way `mut` is used here, the compiler is fine with reassigning the `x` -variable but not the `y` variable. That's because `mut` only applies to the -name that directly follows it, not the whole pattern. For the compiler to allow -you to reassign the `y` variable, you'd need to write the pattern as `(mut x, -mut y)` instead. +Using `mut`, we change the value that `x` binds to from `5` to `6`. ### Variable Binding Scope From 5b94ec1bb6a9c8bae7624aaf137be32ca947529d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 21:33:18 -0400 Subject: [PATCH 090/204] Add a reference now that ownership discusses scope This now isn't the first time you should have seen this if you're reading in order. --- src/ch04-02-variable-bindings-in-detail.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ch04-02-variable-bindings-in-detail.md b/src/ch04-02-variable-bindings-in-detail.md index 9a241cf646..e8c79977e8 100644 --- a/src/ch04-02-variable-bindings-in-detail.md +++ b/src/ch04-02-variable-bindings-in-detail.md @@ -209,9 +209,9 @@ Using `mut`, we change the value that `x` binds to from `5` to `6`. ### Variable Binding Scope -Another important thing to know about variable bindings is that they are only -valid as long as they are *in scope*. That scope begins at the point where the -binding is declared, and ends with the curly brace that closes the block of +As we discussed in the ownership section of Chapter XX, variable bindings are +only valid as long as they are *in scope*. That scope begins at the point where +the binding is declared and ends with the curly brace that closes the block of code containing that binding. We cannot access bindings "before they come into scope" or "after they go out of scope." Here’s an example to illustrate this: From b540f351187979c5583725bc5ccba7adeea5967d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 21:39:29 -0400 Subject: [PATCH 091/204] Removing a reference that I don't think adds much --- src/ch04-02-variable-bindings-in-detail.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch04-02-variable-bindings-in-detail.md b/src/ch04-02-variable-bindings-in-detail.md index e8c79977e8..4688c3082e 100644 --- a/src/ch04-02-variable-bindings-in-detail.md +++ b/src/ch04-02-variable-bindings-in-detail.md @@ -234,7 +234,7 @@ The variable binding for `x` goes out of scope with the last curly brace in the This example only has one scope, though. In Rust, it's possible to create arbitrary scopes within a scope by placing code within another pair of curly -braces (we'll look at this more in the next chapter). For example: +braces. For example: ```rust fn main() { From 9d6b83c64e60becc6b009dd9cd1e9d61e52783ad Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 21:39:57 -0400 Subject: [PATCH 092/204] Remove reference to... references that is now behind us --- src/ch04-02-variable-bindings-in-detail.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ch04-02-variable-bindings-in-detail.md b/src/ch04-02-variable-bindings-in-detail.md index 4688c3082e..7819061092 100644 --- a/src/ch04-02-variable-bindings-in-detail.md +++ b/src/ch04-02-variable-bindings-in-detail.md @@ -266,8 +266,7 @@ fn main() { The `y` variable is only in scope in the section of the code that's between the nested pair of curly braces, whereas `x` is in scope from the `let` statement -that binds it until the final curly brace. The scope of bindings will become -much more important later as you learn about references in Chapter XX. +that binds it until the final curly brace. ### Shadowing Earlier Bindings From c43807117d76f864503e8a36e275cab6b90de7f1 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 21:42:46 -0400 Subject: [PATCH 093/204] Correct the intro paragraph of bindings since stuff was removed --- src/ch04-02-variable-bindings-in-detail.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch04-02-variable-bindings-in-detail.md b/src/ch04-02-variable-bindings-in-detail.md index 7819061092..091ae5cd18 100644 --- a/src/ch04-02-variable-bindings-in-detail.md +++ b/src/ch04-02-variable-bindings-in-detail.md @@ -2,8 +2,8 @@ So far, we’ve created the simplest kind of variable binding, but the `let` statement has some more tricks up its sleeve. Now we'll look at doing more -complex things: creating multiple bindings at once, adding type annotations, -creating mutating bindings, understanding shadowing, and more. +complex things: creating multiple bindings at once, creating mutating bindings, +understanding shadowing, and more. ### Creating Multiple Bindings From 113438d10d1fedb1e3a8915c7d88206518072b98 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 21:44:10 -0400 Subject: [PATCH 094/204] Add a transition from variable bindings to data types --- src/ch04-02-variable-bindings-in-detail.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ch04-02-variable-bindings-in-detail.md b/src/ch04-02-variable-bindings-in-detail.md index 091ae5cd18..759583cdd6 100644 --- a/src/ch04-02-variable-bindings-in-detail.md +++ b/src/ch04-02-variable-bindings-in-detail.md @@ -450,3 +450,5 @@ After shadowing, x is: 5 In this case, the binding value reverts to the original value once the shadow binding goes out of scope. + +Now let's look at some of the types of values that we can bind variables to. From 944e6cc2b98a6deeea2ac7408c4759eacf247651 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 21:49:58 -0400 Subject: [PATCH 095/204] Put back SOME of the let binding stuff about patterns Since it's referred to later. Gloss over a bit more than it was before though. --- src/ch04-01-anatomy-of-a-rust-program.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ch04-01-anatomy-of-a-rust-program.md b/src/ch04-01-anatomy-of-a-rust-program.md index 6094282b12..0b61d6b26b 100644 --- a/src/ch04-01-anatomy-of-a-rust-program.md +++ b/src/ch04-01-anatomy-of-a-rust-program.md @@ -86,16 +86,19 @@ let x = 5; ``` This is a `let` statement, and it binds the value `5` to the variable `x`. -Basic `let` statements take the following form: +`let` statements take the following form: ```text -let NAME = EXPRESSION; +let PATTERN = EXPRESSION; ``` A `let` statement first evaluates the `EXPRESSION` and then binds the resulting -value to `NAME` to give us a variable to use later in the program. Notice the -semicolon at the end of the statement, too. As in many other programming -languages, statements in Rust must end with a semicolon. +value to `PATTERN` to give us a variable to use later in the program. +*Patterns* are part of the *pattern matching* feature of Rust, which will be +covered in more detail in Chapter XX. For now, know that a pattern made of one +name is a simple pattern that matches the value of the entire expression. +Notice the semicolon at the end of the statement, too. As in many other +programming languages, statements in Rust must end with a semicolon. In this simple example, the expression already is a value, but we could achieve the same result like this: From 8f7600ca13dda8de822ddeb3424401b837ea3910 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 22:09:46 -0400 Subject: [PATCH 096/204] Correcting a table caption since we changed the chapter numbers --- src/ch04-03-data-types-in-rust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch04-03-data-types-in-rust.md b/src/ch04-03-data-types-in-rust.md index 52a7677a03..0f56aab134 100644 --- a/src/ch04-03-data-types-in-rust.md +++ b/src/ch04-03-data-types-in-rust.md @@ -92,7 +92,7 @@ built-in integer types in Rust, shown in Table 3-1. | 64-bit | i64 | u64 | | arch | isize | usize | -*Table 3-1: Integer types in Rust. Each code (for example, i32) can be used to +*Table 4-1: Integer types in Rust. Each code (for example, i32) can be used to declare the type of a value.* Each variant can be either signed or unsigned and has an explicit size. Signed From b91d343b670f7feef4042a9896320e196eb6ac0a Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 22:10:19 -0400 Subject: [PATCH 097/204] Remove 'in Rust' from the data types section title Since the whole chapter has "in Rust" in the title. "But isn't the whole book 'in Rust'?" I hear you asking. Well, yes, but this chapter is about programming concepts that exist in other languages and how you do them in Rust. Totes approps imo. --- src/SUMMARY.md | 2 +- src/{ch04-03-data-types-in-rust.md => ch04-03-data-types.md} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/{ch04-03-data-types-in-rust.md => ch04-03-data-types.md} (100%) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 783f5be82c..759103ffb7 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -14,7 +14,7 @@ - [Common Programming Concepts in Rust](ch04-00-common-programming-concepts-in-rust.md) - [Anatomy of a Rust Program](ch04-01-anatomy-of-a-rust-program.md) - [Variable Bindings in Detail](ch04-02-variable-bindings-in-detail.md) - - [Data Types in Rust](ch04-03-data-types-in-rust.md) + - [Data Types](ch04-03-data-types.md) - [How Functions Work](ch04-04-how-functions-work.md) - [Comments](ch04-05-comments.md) - [Control Flow](ch04-06-control-flow.md) diff --git a/src/ch04-03-data-types-in-rust.md b/src/ch04-03-data-types.md similarity index 100% rename from src/ch04-03-data-types-in-rust.md rename to src/ch04-03-data-types.md From 6762e758a8a8754bbcf3f1c612cec114afda8c7c Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 22:12:14 -0400 Subject: [PATCH 098/204] Remove a comment from technical review I forgot to delete --- src/ch04-05-comments.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ch04-05-comments.md b/src/ch04-05-comments.md index 391edb3ec8..cb8eaf3fb6 100644 --- a/src/ch04-05-comments.md +++ b/src/ch04-05-comments.md @@ -42,11 +42,6 @@ That’s all there is to it. Comments are not particularly complicated. ### Documentation Comments - - - Rust has another kind of comment: a *documentation comment*. These comments don’t affect the way that the code works, but they do work with Rust’s tools. More specifically, the `rustdoc` tool can read documentation comments and From 7710118f4e47df0124024bdd29789b163161e069 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 22:15:11 -0400 Subject: [PATCH 099/204] Change -- to : --- src/ch04-03-data-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch04-03-data-types.md b/src/ch04-03-data-types.md index 0f56aab134..2a0119d5fd 100644 --- a/src/ch04-03-data-types.md +++ b/src/ch04-03-data-types.md @@ -143,7 +143,7 @@ Floating-point numbers are represented according to the IEEE-754 standard. The #### Numeric Operations Rust supports the usual basic mathematic operations you’d expect for all of -these number types--addition, subtraction, multiplication, division, and +these number types: addition, subtraction, multiplication, division, and modulo. This code shows how you'd use each one in a `let` statement: ```rust From 1cf14f2baf4d45513ef82648d1888a72329abc93 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 22:17:12 -0400 Subject: [PATCH 100/204] I'm not sure why compound type inside compound type is relevant here --- src/ch04-03-data-types.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ch04-03-data-types.md b/src/ch04-03-data-types.md index 2a0119d5fd..185101a3a9 100644 --- a/src/ch04-03-data-types.md +++ b/src/ch04-03-data-types.md @@ -214,8 +214,7 @@ all unicode code points at *http://www.unicode.org/charts/*. ### Compound Types *Compound types* can group multiple values of other types into one type. Rust -has two primitive compound types: tuples and arrays. You can also put a -compound type inside another compound type. +has two primitive compound types: tuples and arrays. #### Grouping Values into Tuples From 8730203bff33b15f32d0a45e4454051e4a38b994 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 18 Jul 2016 22:27:47 -0400 Subject: [PATCH 101/204] "Long enough" could be ambiguous in this case We get to use underscores in variable bindings once we have a year's experience with them or? --- src/ch04-04-how-functions-work.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch04-04-how-functions-work.md b/src/ch04-04-how-functions-work.md index 07a9483df2..aa1af3bbd2 100644 --- a/src/ch04-04-how-functions-work.md +++ b/src/ch04-04-how-functions-work.md @@ -8,8 +8,8 @@ declare new functions. Rust code uses *snake case* as the conventional style for function names. In snake case, all letters are lower case, and there are underscores separating words. (Rust also uses snake case for the names of variable bindings; we just -haven't used any variable bindings long enough to need underscores yet). Here's -a program containing an example function definition: +haven't used any variable bindings with enough letters to need underscores +yet). Here's a program containing an example function definition: ```rust fn main() { From ec3939fb7368e69ead45635a6a61a29940184809 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 21 Jul 2016 20:42:26 -0400 Subject: [PATCH 102/204] Removing a statement I don't think is true tuples? --- src/ch05-00-structs.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ch05-00-structs.md b/src/ch05-00-structs.md index 5d2bf3d523..14ca0719ae 100644 --- a/src/ch05-00-structs.md +++ b/src/ch05-00-structs.md @@ -1,7 +1,6 @@ # Structs -So far, all of the data types we’ve seen allow us to have a single value -at a time. `struct`s give us the ability to package up multiple values and +`struct`s give us the ability to package up multiple values and keep them in one related structure. Let’s write a program which calculates the distance between two points. From f7103f86b3065d22a65c77e2cf34993478512fdd Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 21 Jul 2016 20:58:04 -0400 Subject: [PATCH 103/204] Give structs a bit more motivation they deserve it --- src/ch05-00-structs.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ch05-00-structs.md b/src/ch05-00-structs.md index 14ca0719ae..b623fe39df 100644 --- a/src/ch05-00-structs.md +++ b/src/ch05-00-structs.md @@ -1,7 +1,12 @@ # Structs -`struct`s give us the ability to package up multiple values and -keep them in one related structure. +`struct`s, short for "structures", give us the ability to name and package +together multiple related values that make up a meaningful group. If you come +from an object-oriented language, `struct`s are like an object's data +attributes. `structs`, along with `enum`s that we talked about in the last +chapter, are the building blocks you can use in Rust to create new types in +your program's domain in order to take full advantage of Rust's compile-time +type checking. Let’s write a program which calculates the distance between two points. We’ll start off with single variable bindings, and then refactor it to From 507a668cb014605291fc9092d325e293f629e6ef Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 21 Jul 2016 21:48:41 -0400 Subject: [PATCH 104/204] I'm not sure what Pythagoras did to Steve, buuuut This actually could use a bit of stating in words, imo. And I don't feel like we need to repeat the function so close to the original code containing it. --- src/ch05-00-structs.md | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/ch05-00-structs.md b/src/ch05-00-structs.md index b623fe39df..7574d6ca87 100644 --- a/src/ch05-00-structs.md +++ b/src/ch05-00-structs.md @@ -56,21 +56,18 @@ Point 2: (12, 0) Distance: 13 ``` -Let's take a quick look at `distance()` before we move forward: - -```rust -fn distance(x1: f64, y1: f64, x2: f64, y2: f64) -> f64 { - let x_squared = f64::powi(x2 - x1, 2); - let y_squared = f64::powi(y2 - y1, 2); - - f64::sqrt(x_squared + y_squared) -} -``` - -To find the distance between two points, we can use the Pythagorean Theorem. -The theorem is named after Pythagoras, who was the first person to mathematically -prove this formula. The details aren't that important, to be honest. There's a few -things that we haven't discussed yet, though. +Let's take a quick look at `distance()` before we move forward. To find the +distance between two points, we can use the Pythagorean Theorem. The theorem is +named after Pythagoras, who was the first person to mathematically prove this +formula. The details aren't that important; just know the theorem says that the +formula for the distance between two points is equal to: + +- squaring the distance between the points horizontally (the "x" direction) +- squaring the distance between the points vertically (the "y" direction) +- adding those together +- and taking the square root of that. + +So that's what we're implementing here. ```rust,ignore f64::powi(2.0, 3) From c56d76de65327710d4eb855acf064076efb6cfba Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 21 Jul 2016 21:50:45 -0400 Subject: [PATCH 105/204] We did see namespaces a bit, in ownership with `String::from` --- src/ch05-00-structs.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ch05-00-structs.md b/src/ch05-00-structs.md index 7574d6ca87..23ea61fe34 100644 --- a/src/ch05-00-structs.md +++ b/src/ch05-00-structs.md @@ -74,12 +74,13 @@ f64::powi(2.0, 3) ``` The double colon (`::`) here is a namespace operator. We haven’t talked about -modules yet, but you can think of the `powi()` function as being scoped inside -of another name. In this case, the name is `f64`, the same as the type. The -`powi()` function takes two arguments: the first is a number, and the second is -the power that it raises that number to. In this case, the second number is an -integer, hence the ‘i’ in its name. Similarly, `sqrt()` is a function under the -`f64` module, which takes the square root of its argument. +modules and namespaces in depth yet, but you can think of the `powi()` function +as being scoped inside of another name. In this case, the name is `f64`, the +same as the type. The `powi()` function takes two arguments: the first is a +number, and the second is the power that it raises that number to. In this +case, the second number is an integer, hence the ‘i’ in its name. Similarly, +`sqrt()` is a function under the `f64` module, which takes the square root of +its argument. ## Why `struct`s? From cf3e963e3f97aba5193bf7aee08640727cc26a01 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 21 Jul 2016 21:51:45 -0400 Subject: [PATCH 106/204] Minor wording/punctuation/spelling changes --- src/ch05-00-structs.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/ch05-00-structs.md b/src/ch05-00-structs.md index 23ea61fe34..37edf4d92e 100644 --- a/src/ch05-00-structs.md +++ b/src/ch05-00-structs.md @@ -84,8 +84,8 @@ its argument. ## Why `struct`s? -Our little program is okay, but we can do better. The key is in the signature -of `distance()`: +Our little program is okay, but we can do better. The key to seeing this is in +the signature of `distance()`: ```rust,ignore fn distance(x1: f64, y1: f64, x2: f64, y2: f64) -> f64 { @@ -94,11 +94,11 @@ fn distance(x1: f64, y1: f64, x2: f64, y2: f64) -> f64 { The distance function is supposed to calculate the distance between two points. But our distance function calculates some distance between four numbers. The first two and last two arguments are related, but that’s not expressed anywhere -in our program itself. We need a way to group `(x1, y1)` and `(x2, y2)` -together. +in our program itself. It would be nicer if we had a way to group `(x1, y1)` +and `(x2, y2)` together. -We’ve already discussed one way to do that: tuples. Here’s a version of our program -which uses tuples: +We’ve already discussed one way to do that: tuples. Here’s a version of our +program which uses tuples: ```rust fn main() { @@ -122,9 +122,9 @@ fn distance(p1: (f64, f64), p2: (f64, f64)) -> f64 { ``` This is a little better, for sure. Tuples let us add a little bit of structure. -We’re now passing two arguments, so that’s more clear. But it’s also worse. -Tuples don’t give names to their elements, and so our calculation has gotten -much more confusing: +We’re now passing two arguments, so that’s more clear. But it’s also worse: +tuples don’t give names to their elements, so our calculation has gotten more +confusing: ```rust,ignore p2.0 - p1.0 @@ -132,10 +132,11 @@ p2.1 - p1.1 ``` When writing this example, your authors almost got it wrong themselves! Distance -is all about `x` and `y` points, but now it’s all about `0` and `1`. This isn’t -great. +is all about `x` and `y` points, but our code is talking about `0` and `1`. +This isn’t great. -Enter `struct`s. We can transform our tuples into something with a name: +Enter `struct`s. We can transform our tuples into something with a name for the +whole as well as names for the parts: ```rust,ignore let p1 = (0.0, 5.0); @@ -148,7 +149,7 @@ struct Point { let p1 = Point { x: 0.0, y: 5.0 }; ``` -Here’s what declaring a `struct` looks like: +Here’s what declaring a `struct` looks like in general: ```text struct NAME { From afbbb0de4aefcbb6f49f5cd5a83e29f38c9f54ec Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 21 Jul 2016 21:52:15 -0400 Subject: [PATCH 107/204] Cut discussion of unit structs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit es-o-ter-ic 👏👏, 👏👏👏 --- src/ch05-00-structs.md | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/ch05-00-structs.md b/src/ch05-00-structs.md index 37edf4d92e..db613400d8 100644 --- a/src/ch05-00-structs.md +++ b/src/ch05-00-structs.md @@ -158,17 +158,10 @@ struct NAME { ``` The `NAME: TYPE` bit is called a ‘field’, and we can have as many or as few of -them as you’d like. If you have none of them, drop the `{}`s: +them as we’d like. -```rust -struct Foo; -``` - -`struct`s with no fields are called ‘unit structs’, and are used in certain -advanced situations. We will just ignore them for now. - -You can access the field of a struct in the same way you access an element of -a tuple, except you use its name: +We can access the field of a struct in the same way we access an element of +a tuple, except we use its name: ```rust,ignore let p1 = (0.0, 5.0); From ca7a5f39d6b8329d29fbd795dcc85bc776d84269 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 21 Jul 2016 21:53:08 -0400 Subject: [PATCH 108/204] Change discussion of `derive`/annotations/traits to match reorg --- src/ch05-00-structs.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ch05-00-structs.md b/src/ch05-00-structs.md index db613400d8..dcaffb211f 100644 --- a/src/ch05-00-structs.md +++ b/src/ch05-00-structs.md @@ -210,7 +210,7 @@ Our function signature for `distance()` now says exactly what we mean: it calculates the distance between two `Point`s. And rather than `0` and `1`, we’ve got back our `x` and `y`. This is a win for clarity. -There’s one other thing that’s a bit strange here, this annotation on our +There’s one other thing that’s a bit strange here, this stuff above the `struct` declaration: ```rust,ignore @@ -218,7 +218,10 @@ There’s one other thing that’s a bit strange here, this annotation on our struct Point { ``` -We haven’t yet talked about traits, but we did talk about `Debug` when we -discussed arrays. This `derive` attribute allows us to tweak the behavior of -our `Point`. In this case, we are opting into copy semantics, and everything -that implements `Copy` must implement `Clone`. +This is an annotation that tells the compiler our struct should get some +default behavior for the `Debug`, `Copy`, and `Clone` traits. We talked about +`Debug` when we discussed arrays-- this lets us print out the `struct` and all +its fields when we use an instance of the struct with `println!`'s `{:?}`. We +talked about marking that types can be `Copy` and `Clone`-able in Chapter XX +when we discussed ownership. We'll continue exploring annotations and the +behaviors you can `derive` in Chapter XX. From 582a73b19b4c9e3ab2abf033719fb14700ba723e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 27 Jul 2016 22:22:38 +0200 Subject: [PATCH 109/204] Update ch06-04-if-let.md I read it more easily this way --- src/ch06-04-if-let.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch06-04-if-let.md b/src/ch06-04-if-let.md index 0efe5605a7..a9748e7841 100644 --- a/src/ch06-04-if-let.md +++ b/src/ch06-04-if-let.md @@ -16,8 +16,8 @@ match some_option { We care about the `Some` case, but don't want to do anything with the `None` 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 +this boilerplate arm and 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 others." From 09909d27d6a2a176a32ac5fdce063102fc1b6186 Mon Sep 17 00:00:00 2001 From: Zachary T Jones Date: Wed, 27 Jul 2016 20:29:17 -0400 Subject: [PATCH 110/204] Fix typos/grammar and markdown link syntax --- src/ch04-02-ownership.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index 5083c135d4..e43ff22f14 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -206,7 +206,7 @@ it only works for memory. What if, instead of a `String`, we had a `TcpConnection`? Opening and closing a network connection is very similar to allocating and freeing memory. The solution that we could use there is to allow the programmer to hook into the assignment, similar to `drop()`, and write code -fix things up. That would work, but now, an `=` can run arbitrary code. That’s +to fix things up. That would work, but now, an `=` can run arbitrary code. That’s also not good, and it doesn’t solve our efficiency concerns either. Let’s take a step back: the root of the problem is that `s1` and `s2` both @@ -258,7 +258,7 @@ inexpensive. But what if we _do_ want to deeply copy the `String`’s data, and not just the `String` itself? There’s a common method for that: `clone()`. We will discuss -methods in the next section on [`struct`]s, but they’re a common enough feature +methods in the next section on [structs][struct], but they’re a common enough feature in many programming languages that you have probably seen them before. Here’s an example of the `clone()` method in action: @@ -270,7 +270,7 @@ let s2 = s1.clone(); println!("{}", s1); ``` -[`struct`]: structs.html +[struct]: structs.html This will work just fine. Remember our diagram from before? In this case, it _is_ doing this: @@ -442,7 +442,7 @@ owner goes out of scope, if it hasn’t been moved, it will `drop()`. This might seem a bit tedious, and it is. What if I want to let a function use a value, but not take ownership? It’s quite annoying that anything I pass in -also needs passed back. Look at this function: +also needs to be passed back. Look at this function: ```rust fn main() { From 0adad8df42dfd2b4f762d1c2fd7980b1ffca0454 Mon Sep 17 00:00:00 2001 From: Zachary T Jones Date: Thu, 28 Jul 2016 13:08:42 -0400 Subject: [PATCH 111/204] Update link to structs chapter --- src/ch04-02-ownership.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index e43ff22f14..adb1419643 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -258,7 +258,7 @@ inexpensive. But what if we _do_ want to deeply copy the `String`’s data, and not just the `String` itself? There’s a common method for that: `clone()`. We will discuss -methods in the next section on [structs][struct], but they’re a common enough feature +methods in the next section on [structs], but they’re a common enough feature in many programming languages that you have probably seen them before. Here’s an example of the `clone()` method in action: @@ -270,7 +270,7 @@ let s2 = s1.clone(); println!("{}", s1); ``` -[struct]: structs.html +[structs]: ch05-01-structs.html This will work just fine. Remember our diagram from before? In this case, it _is_ doing this: From bd6539e2b20ce2cb70e11c4ecd09b6aa7cc914ff Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 25 Jul 2016 12:36:17 -0400 Subject: [PATCH 112/204] Remove a spurious space --- src/ch03-02-references-and-borrowing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch03-02-references-and-borrowing.md b/src/ch03-02-references-and-borrowing.md index c1e097abc4..c407298708 100644 --- a/src/ch03-02-references-and-borrowing.md +++ b/src/ch03-02-references-and-borrowing.md @@ -292,7 +292,7 @@ Here’s a recap of what we’ve talked about: 1. At any given time, you may have _either_, but not both of: 1. One mutable reference. - 2. Any number of immutable references . + 2. Any number of immutable references. 2. References must always be valid. Next, let's look at a different kind of reference: slices. From eb82716d3c26e750a6900e4605b09acd628e15bd Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 28 Jul 2016 15:55:38 -0400 Subject: [PATCH 113/204] Remove some more "in Rust" from titles --- src/ch04-03-data-types.md | 2 +- src/ch04-04-how-functions-work.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch04-03-data-types.md b/src/ch04-03-data-types.md index 185101a3a9..5f4ee1dfcd 100644 --- a/src/ch04-03-data-types.md +++ b/src/ch04-03-data-types.md @@ -1,4 +1,4 @@ -## Data Types in Rust +## Data Types Every value in Rust is of a certain *type*, which tells Rust what kind of data is being given so it knows how to work with that data. You can usually rely on diff --git a/src/ch04-04-how-functions-work.md b/src/ch04-04-how-functions-work.md index aa1af3bbd2..413455b34b 100644 --- a/src/ch04-04-how-functions-work.md +++ b/src/ch04-04-how-functions-work.md @@ -1,4 +1,4 @@ -## How Functions Work in Rust +## How Functions Work Functions are pervasive in Rust code. We’ve already seen one of the most important functions in the language: the `main()` function that’s the entry From dfc49051bdf5b05e3549efaa4b0956843ff3e2cd Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 28 Jul 2016 15:48:06 -0700 Subject: [PATCH 114/204] Update errors in references chapter --- src/ch03-02-references-and-borrowing.md | 75 ++++++++++++------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/src/ch03-02-references-and-borrowing.md b/src/ch03-02-references-and-borrowing.md index c407298708..baff5bf009 100644 --- a/src/ch03-02-references-and-borrowing.md +++ b/src/ch03-02-references-and-borrowing.md @@ -106,10 +106,12 @@ fn change(some_string: &String) { Here’s the error: -```bash -8:16 error: cannot borrow immutable borrowed content `*some_string` as mutable - some_string.push_str(", world"); - ^~~~~~~~~~~ +```text +error: cannot borrow immutable borrowed content `*some_string` as mutable + --> error.rs:8:5 + | +8 | some_string.push_str(", world"); + | ^^^^^^^^^^^ ``` Just like bindings are immutable by default, so are references. We’re not @@ -146,20 +148,16 @@ let r2 = &mut s; Here’s the error: -```bash -5:20 error: cannot borrow `s` as mutable more than once at a time [E0499] - let r2 = &mut s; - ^ -4:20 note: previous borrow of `s` occurs here; the mutable borrow prevents - subsequent moves, borrows, or modification of `s` until the borrow - ends - let r1 = &mut s; - ^ -7:2 note: previous borrow ends here -fn main() { - -} -^ +```text +error[E0499]: cannot borrow `s` as mutable more than once at a time + --> borrow_twice.rs:5:19 + | +4 | let r1 = &mut s; + | - first mutable borrow occurs here +5 | let r2 = &mut s; + | ^ second mutable borrow occurs here +6 | } + | - first borrow ends here ``` The error is what it says: you cannot borrow something mutably more than once @@ -195,20 +193,16 @@ let r3 = &mut s; // BIG PROBLEM Here’s the error: ```text -19: 6:20 error: cannot borrow `s` as mutable because it is also borrowed as - immutable [E0502] - let r3 = &mut s; // BIG PROBLEM - ^ -15: 4:16 note: previous borrow of `s` occurs here; the immutable borrow - prevents subsequent moves or mutable borrows of `s` until the - borrow ends - let r1 = &s; // no problem - ^ -8:2 note: previous borrow ends here -fn main() { - -} -^ +error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable + --> borrow_thrice.rs:6:19 + | +4 | let r1 = &s; // no problem + | - immutable borrow occurs here +5 | let r2 = &s; // no problem +6 | let r3 = &mut s; // BIG PROBLEM + | ^ mutable borrow occurs here +7 | } + | - immutable borrow ends here ``` Whew! We _also_ cannot have a mutable reference while we have an immutable one. @@ -240,12 +234,17 @@ fn dangle() -> &String { Here’s the error: ```text -error: missing lifetime specifier [E0106] -fn dangle() -> &String { - ^~~~~~~ -help: this function’s return type contains a borrowed value, but there is no - value for it to be borrowed from -help: consider giving it a 'static lifetime +error[E0106]: missing lifetime specifier + --> dangle.rs:5:16 + | +5 | fn dangle() -> &String { + | ^^^^^^^ + | + = help: this function's return type contains a borrowed value, but there is no + value for it to be borrowed from + = help: consider giving it a 'static lifetime + +error: aborting due to previous error ``` This error message refers to a feature we haven’t learned about yet, From 36d022f7298a92d4106c3e94b8772939789fbbe4 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 28 Jul 2016 20:11:51 -0400 Subject: [PATCH 115/204] Rewrite the intro to be friendlier and more welcoming Fixes #149. --- src/ch01-00-introduction.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/ch01-00-introduction.md b/src/ch01-00-introduction.md index 51f618b3c0..631227bb06 100644 --- a/src/ch01-00-introduction.md +++ b/src/ch01-00-introduction.md @@ -2,26 +2,26 @@ Welcome to “The Rust Programming Language”, an introductory book about Rust. Rust is a programming language that’s focused on safety, concurrency, and -speed. It maintains these goals without having a garbage collector, making it a -useful language for a number of use cases other languages aren’t good at: -embedding in other languages, programs with specific space and time -requirements, and writing low-level code, like device drivers and operating -systems. It improves on current languages targeting this space by having a -number of compile-time safety checks that produce no runtime overhead, while -eliminating all data races. Rust also aims to achieve ‘zero-cost abstractions’ -even though some of these abstractions feel like those of a high-level -language. Even then, Rust still allows precise control like a low-level -language would. +speed. Its design lets you create programs that have the speed and control of a +low-level language, but with helpful abstractions that feel like a high-level +language. The Rust community welcomes all programmers who have their experience +in languages like C and are looking for a safer alternative, as well as +programmers from languages like Ruby who are looking for ways to write more +performant code without losing expressiveness. -This book is written for a reader who already knows how to program in at least -one programming language. Which language that is does not matter very much, -though you may have an easier time if you’ve programmed in a low-level language -with manual memory allocation. +Rust provides the majority of its safety checks at compile time and without a +garbage collector so that your program's runtime isn't impacted. This makes it +useful in a number of use cases that other languages aren’t good at: embedding +in other languages, programs with specific space and time requirements, and +writing low-level code, like device drivers and operating systems. It's also +great for web applications: it powers the Rust package registry site, crates.io! +We're excited to see what _you_ create with Rust. -After reading this book, you should be comfortable writing Rust programs. We’ll -be learning Rust through small, focused examples that demonstrate each topic. -The chapters build upon each other, so if you skip ahead, you may have to skip -back to refer to a previous concept. +This book is written for a reader who already knows how to program in at least +one programming language. After reading this book, you should be comfortable +writing Rust programs. We’ll be learning Rust through small, focused examples +that build on each other to demonstrate how to use various features of Rust as +well as how they work behind the scenes. ## Contributing to the book From ec255d22f3c27b6a27d6e07d72ba1e3d702f195e Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 28 Jul 2016 20:38:29 -0400 Subject: [PATCH 116/204] Address comments about the installation section Fixes #150. --- src/ch01-01-installation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ch01-01-installation.md b/src/ch01-01-installation.md index 11056e4f82..f56d94a075 100644 --- a/src/ch01-01-installation.md +++ b/src/ch01-01-installation.md @@ -1,8 +1,8 @@ # Installation -The first step to using Rust is to install it. Generally speaking, you’ll need -an internet connection to run the commands in this chapter, as we’ll be -downloading Rust from the internet. +The first step to using Rust is to install it. You’ll need an internet +connection to run the commands in this chapter, as we’ll be downloading Rust +from the internet. We’ll be showing off a number of commands using a terminal, and those lines all start with `$`. You don't need to type in the `$`s, they are there to indicate From dd8d7766146cc6fa540752e7d91dcb77c26a6d8f Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 28 Jul 2016 20:40:57 -0400 Subject: [PATCH 117/204] Small wording, punctuation, and wrapping edits to installation --- src/ch01-01-installation.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ch01-01-installation.md b/src/ch01-01-installation.md index f56d94a075..4172130f6f 100644 --- a/src/ch01-01-installation.md +++ b/src/ch01-01-installation.md @@ -5,27 +5,27 @@ connection to run the commands in this chapter, as we’ll be downloading Rust from the internet. We’ll be showing off a number of commands using a terminal, and those lines all -start with `$`. You don't need to type in the `$`s, they are there to indicate +start with `$`. You don't need to type in the `$`s; they are there to indicate the start of each command. You’ll see many tutorials and examples around the web that follow this convention: `$` for commands run as a regular user, and `#` for commands you should be running as an administrator. ## Installing on Linux or Mac -If you're on Linux or a Mac, all you need to do is open a terminal and type this: +If you're on Linux or a Mac, all you need to do is open a terminal and type +this: ```bash $ curl -sSf https://static.rust-lang.org/rustup.sh | sh ``` -This will download a script, and start the installation. You may be prompted for your password. -If it all goes well, you’ll see this appear: +This will download a script and start the installation. You may be prompted for +your password. If it all goes well, you’ll see this appear: ```text Rust is ready to roll. ``` - ## Installing on Windows If you're on Windows, please download the appropriate [installer][install-page]. @@ -41,8 +41,8 @@ the uninstall script: $ sudo /usr/local/lib/rustlib/uninstall.sh ``` -If you used the Windows installer, you can re-run the `.msi` and it will give you -an uninstall option. +If you used the Windows installer, you can re-run the `.msi` and it will give +you an uninstall option. ## Troubleshooting From 8af84e7514be2a3aa72e3a421925cf68cb73f342 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 28 Jul 2016 20:51:28 -0400 Subject: [PATCH 118/204] Replace rustup.sh with rustup.rs --- src/ch01-01-installation.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ch01-01-installation.md b/src/ch01-01-installation.md index 4172130f6f..94dafd2ba0 100644 --- a/src/ch01-01-installation.md +++ b/src/ch01-01-installation.md @@ -16,14 +16,14 @@ If you're on Linux or a Mac, all you need to do is open a terminal and type this: ```bash -$ curl -sSf https://static.rust-lang.org/rustup.sh | sh +$ curl https://sh.rustup.rs -sSf | sh ``` This will download a script and start the installation. You may be prompted for your password. If it all goes well, you’ll see this appear: ```text - Rust is ready to roll. +Rust is installed now. Great! ``` ## Installing on Windows @@ -38,7 +38,7 @@ Uninstalling Rust is as easy as installing it. On Linux or Mac, just run the uninstall script: ```bash -$ sudo /usr/local/lib/rustlib/uninstall.sh +$ rustup self uninstall ``` If you used the Windows installer, you can re-run the `.msi` and it will give @@ -64,7 +64,7 @@ If not, there are a number of places where you can get help. The easiest is [the #rust IRC channel on irc.mozilla.org][irc], which you can access through [Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans (a silly nickname we call ourselves) who can help you out. Other great resources -include [the user’s forum][users], and [Stack Overflow][stackoverflow]. +include [the user’s forum][users] and [Stack Overflow][stackoverflow]. [irc]: irc://irc.mozilla.org/#rust [mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust @@ -73,7 +73,7 @@ include [the user’s forum][users], and [Stack Overflow][stackoverflow]. ## Local documentation -This installer also installs a copy of the documentation locally, so you can -read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location. -On Windows, it's in a `share/doc` directory, inside the directory to which Rust -was installed. +The installer also includes a copy of the documentation locally, so you can +read it offline. On Linux or Mac, run `rustup doc` to open the local +documentation in your browser. On Windows, the documentation is in a +`share/doc` directory inside the directory where Rust was installed. From 71a91c4db438e5ae8b73e76e13dcf450361baa48 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 28 Jul 2016 20:53:21 -0400 Subject: [PATCH 119/204] Show an example of rustc --version output, with placeholders Fixes #151. --- src/ch01-01-installation.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ch01-01-installation.md b/src/ch01-01-installation.md index 94dafd2ba0..d8bc753217 100644 --- a/src/ch01-01-installation.md +++ b/src/ch01-01-installation.md @@ -52,9 +52,15 @@ If you've got Rust installed, you can open up a shell, and type this: $ rustc --version ``` -You should see the version number, commit hash, and commit date. +You should see the version number, commit hash, and commit date in a format +similar to this for the latest stable version at the time you install: -If you do, Rust has been installed successfully! Congrats! +```bash +rustc x.y.z (abcabcabc yyyy-mm-dd) +``` + +If you see this, Rust has been installed successfully! +Congrats! If you don't and you're on Windows, check that Rust is in your %PATH% system variable. If it isn't, run the installer again, select "Change" on the "Change, From bb0ac803e7fee7ff18b2203093e4923dfd3d9a0d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 28 Jul 2016 21:26:35 -0400 Subject: [PATCH 120/204] Inspired by hello world, clarify `$` further Too much? --- src/ch01-01-installation.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ch01-01-installation.md b/src/ch01-01-installation.md index d8bc753217..3e669a5b37 100644 --- a/src/ch01-01-installation.md +++ b/src/ch01-01-installation.md @@ -8,7 +8,8 @@ We’ll be showing off a number of commands using a terminal, and those lines al start with `$`. You don't need to type in the `$`s; they are there to indicate the start of each command. You’ll see many tutorials and examples around the web that follow this convention: `$` for commands run as a regular user, and `#` -for commands you should be running as an administrator. +for commands you should be running as an administrator. Lines that don't start +with `$` are typically showing the output of the previous command. ## Installing on Linux or Mac From f96b0b0ed1dc1fb5f2889e96be7bfd3c4ffd9e17 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 28 Jul 2016 21:27:12 -0400 Subject: [PATCH 121/204] Change output highlighting from text to bash --- src/ch01-01-installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch01-01-installation.md b/src/ch01-01-installation.md index 3e669a5b37..bce9f41312 100644 --- a/src/ch01-01-installation.md +++ b/src/ch01-01-installation.md @@ -23,7 +23,7 @@ $ curl https://sh.rustup.rs -sSf | sh This will download a script and start the installation. You may be prompted for your password. If it all goes well, you’ll see this appear: -```text +```bash Rust is installed now. Great! ``` From 0e7e64a49508aeb31cb3d7013ff184e378f03513 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 28 Jul 2016 21:27:53 -0400 Subject: [PATCH 122/204] Small wording, punctuation, etc edits to hello world --- src/ch01-02-hello-world.md | 45 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/ch01-02-hello-world.md b/src/ch01-02-hello-world.md index 92fb254f08..db4045c857 100644 --- a/src/ch01-02-hello-world.md +++ b/src/ch01-02-hello-world.md @@ -1,4 +1,4 @@ -# Hello, world! +# Hello, World! Now that you have Rust installed, let’s write your first Rust program. It's traditional when learning a new language to write a little program to print the @@ -17,9 +17,9 @@ practicing it early on is good. ## Creating a Project File First, make a file to put your Rust code in. Rust doesn't care where your code -lives, but for this book, I suggest making a *projects* directory in your home -directory, and keeping all your projects there. Open a terminal and enter the -following commands to make a directory for this particular project: +lives, but for this book, we'd suggest making a *projects* directory in your +home directory and keeping all your projects there. Open a terminal and enter +the following commands to make a directory for this particular project: ```bash $ mkdir ~/projects @@ -28,14 +28,15 @@ $ mkdir hello_world $ cd hello_world ``` -> Note: If you’re on Windows and not using PowerShell, the `~` may not work. +> Note: If you’re on Windows and not using PowerShell, the `~` that represents +> your home directory may not work. > Consult the documentation for your shell for more details. ## Writing and Running a Rust Program Next, make a new source file and call it *main.rs*. Rust files always end in a *.rs* extension. If you’re using more than one word in your filename, use -an underscore to separate them; for example, you'd use *hello_world.rs* rather +an underscore to separate them. For example, you'd use *hello_world.rs* rather than *helloworld.rs*. Now open the *main.rs* file you just created, and type the following code: @@ -60,7 +61,7 @@ system, you should see the string `Hello, world!` print to the terminal. If you did, then congratulations! You've officially written a Rust program. That makes you a Rust programmer! Welcome. -## Anatomy of a Rust Program +## Hello, World Explained Now, let’s go over what just happened in your "Hello, world!" program in detail. Here's the first piece of the puzzle: @@ -72,11 +73,11 @@ fn main() { ``` These lines define a *function* in Rust. The `main` function is special: it's -the beginning of every Rust program. The first line says, “I’m declaring a -function named `main` that takes no arguments and returns nothing.” If there -were arguments, they would go inside the parentheses (`(` and `)`), and because -we aren’t returning anything from this function, we can omit the return type -entirely. +the first thing that is run for every executable Rust program. The first line +says, “I’m declaring a function named `main` that takes no arguments and +returns nothing.” If there were arguments, they would go inside the parentheses +(`(` and `)`), because we aren’t returning anything from this function, we +have omitted the return type entirely. Also note that the function body is wrapped in curly braces (`{` and `}`). Rust requires these around all function bodies. It's considered good style to put @@ -94,14 +95,12 @@ screen. There are a number of details that are important here. The first is that it’s indented with four spaces, not tabs. The second important part is the `println!()` line. This is calling a Rust -*[macro]*, which is how metaprogramming is done in Rust. If it were calling a +*macro*, which is how metaprogramming is done in Rust. If it were calling a function instead, it would look like this: `println()` (without the !). We'll -discuss Rust macros in more detail later, but for now you just need to +discuss Rust macros in more detail in Chapter XX, but for now you just need to know that when you see a `!` that means that you’re calling a macro instead of a normal function. -[macro]: macros.html - Next is `"Hello, world!"` which is a *string*. We pass this string as an argument to `println!`, which prints the string to the screen. Easy enough! @@ -154,15 +153,15 @@ world!` to your terminal. If you come from a dynamic language like Ruby, Python, or JavaScript, you may not be used to compiling and running a program being separate steps. Rust is an *ahead-of-time compiled* language, which means that you can compile a program, -give it to someone else, and they can run it even without Rust installed. If -you give someone a `.rb` or `.py` or `.js` file, on the other hand, they need -to have a Ruby, Python, or JavaScript implementation installed (respectively), -but you only need one command to both compile and run your program. Everything -is a tradeoff in language design. +give it to someone else, and they can run it even without having Rust +installed. If you give someone a `.rb`, `.py`, or `.js` file, on the other +hand, they need to have a Ruby, Python, or JavaScript implementation installed +(respectively), but you only need one command to both compile and run your +program. Everything is a tradeoff in language design. Just compiling with `rustc` is fine for simple programs, but as your project -grows, you'll want to be able to manage all of the options your project has, -and make it easy to share your code with other people and projects. Next, I'll +grows, you'll want to be able to manage all of the options your project has +and make it easy to share your code with other people and projects. Next, we'll introduce you to a tool called Cargo, which will help you write real-world Rust programs. From 8e2ae1cfa6757a635a4926bd0a172dd0224e4593 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Thu, 28 Jul 2016 21:28:17 -0400 Subject: [PATCH 123/204] Remove motivation for hello world and "expression based" Fixes #152. --- src/ch01-02-hello-world.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/ch01-02-hello-world.md b/src/ch01-02-hello-world.md index db4045c857..874867dac1 100644 --- a/src/ch01-02-hello-world.md +++ b/src/ch01-02-hello-world.md @@ -5,11 +5,6 @@ traditional when learning a new language to write a little program to print the text “Hello, world!” to the screen, and in this section, we'll follow that tradition. -The nice thing about starting with such a simple program is that you can -quickly verify that your compiler is installed, and that it's working properly. -Printing information to the screen is also just a pretty common thing to do, so -practicing it early on is good. - > Note: This book assumes basic familiarity with the command line. Rust itself > makes no specific demands about your editing, tooling, or where your code > lives, so if you prefer an IDE to the command line, that's an option. @@ -104,10 +99,9 @@ a normal function. Next is `"Hello, world!"` which is a *string*. We pass this string as an argument to `println!`, which prints the string to the screen. Easy enough! -The line ends with a semicolon (`;`). Rust is an *expression oriented* -language, which means that most things are expressions, rather than statements. -The `;` indicates that this expression is over, and the next one is ready to -begin. Most lines of Rust code end with a `;`. +The line ends with a semicolon (`;`). The `;` indicates that this expression is +over, and the next one is ready to begin. Most lines of Rust code end with a +`;`. ## Compiling and Running Are Separate Steps From 2cb1773fabd60e570cb023698d660fb9029379d7 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 29 Jul 2016 08:51:26 -0400 Subject: [PATCH 124/204] Safety, speed, concurrency. Don't repeat speed so soon --- src/ch01-00-introduction.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ch01-00-introduction.md b/src/ch01-00-introduction.md index 631227bb06..d21532509f 100644 --- a/src/ch01-00-introduction.md +++ b/src/ch01-00-introduction.md @@ -1,12 +1,12 @@ # Introduction Welcome to “The Rust Programming Language”, an introductory book about Rust. -Rust is a programming language that’s focused on safety, concurrency, and -speed. Its design lets you create programs that have the speed and control of a -low-level language, but with helpful abstractions that feel like a high-level -language. The Rust community welcomes all programmers who have their experience -in languages like C and are looking for a safer alternative, as well as -programmers from languages like Ruby who are looking for ways to write more +Rust is a programming language that’s focused on safety, speed, and +concurrency. Its design lets you create programs that have the performance and +control of a low-level language, but with helpful abstractions that feel like a +high-level language. The Rust community welcomes all programmers who have their +experience in languages like C and are looking for a safer alternative, as well +as programmers from languages like Ruby who are looking for ways to write more performant code without losing expressiveness. Rust provides the majority of its safety checks at compile time and without a From 17429f2322934dc91ead921257c235268ceed538 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 29 Jul 2016 08:51:52 -0400 Subject: [PATCH 125/204] Ruby -> Python --- src/ch01-00-introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch01-00-introduction.md b/src/ch01-00-introduction.md index d21532509f..badc112910 100644 --- a/src/ch01-00-introduction.md +++ b/src/ch01-00-introduction.md @@ -6,7 +6,7 @@ concurrency. Its design lets you create programs that have the performance and control of a low-level language, but with helpful abstractions that feel like a high-level language. The Rust community welcomes all programmers who have their experience in languages like C and are looking for a safer alternative, as well -as programmers from languages like Ruby who are looking for ways to write more +as programmers from languages like Python who are looking for ways to write more performant code without losing expressiveness. Rust provides the majority of its safety checks at compile time and without a From 4e73350c086bdf48bd903e6b05de85e39f8fcf29 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 29 Jul 2016 10:43:26 -0700 Subject: [PATCH 126/204] Split up example for better readability --- src/ch03-03-slices.md | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/ch03-03-slices.md b/src/ch03-03-slices.md index af466fe9e9..889d423bc3 100644 --- a/src/ch03-03-slices.md +++ b/src/ch03-03-slices.md @@ -37,38 +37,39 @@ fn first_word(s: &String) -> usize { Let’s break that down a bit: ```rust -fn first_word(s: &String) -> usize { - - // Since we need to go through the String element by element and - // check if a value is a space, we will convert our String to an - // array of bytes using the `.as_bytes()` method. let bytes = s.as_bytes(); +``` - // We will be discussing iterators in more detail in Chapter XX, but for - // now, know that `iter()` is a method that returns each element in a - // collection, and `enumerate()` modifies the result of `iter()` and returns - // a tuple instead. The first element of the tuple is the index, and the - // second element is a reference to the element itself. This is a bit - // nicer than calculating the index ourselves. - // - // Since it’s a tuple, we can use patterns, just like elsewhere in Rust. - // So we match against the tuple with i for the index and &byte for - // the byte itself. +Since we need to go through the String element by element and +check if a value is a space, we will convert our String to an +array of bytes using the `.as_bytes()` method. + +```rust for (i, &byte) in bytes.iter().enumerate() { +``` - // 32 is the value of a space in UTF-8 +We will be discussing iterators in more detail in Chapter XX, but for +now, know that `iter()` is a method that returns each element in a +collection, and `enumerate()` modifies the result of `iter()` and returns +a tuple instead. The first element of the tuple is the index, and the +second element is a reference to the element itself. This is a bit +nicer than calculating the index ourselves. + +Since it’s a tuple, we can use patterns, just like elsewhere in Rust. +So we match against the tuple with i for the index and &byte for +the byte itself. + +```rust if byte == 32 { - // We found a space! Return this position. return i; } } - - // If we got here, we didn’t find a space, so the whole string must be a - // word. Return the length. s.len() -} ``` +We search for the value 32, which represents a space in UTF-8. If we find one, we return the +position. Otherwise, we return the length of the string, using `s.len()`. + This works, but there’s a problem. We’re returning a `usize` on its own, but it’s only a meaningful number in the context of the `&String`. In other words, because it’s a separate value from the `String`, there’s no guarantee From 4b7a42814ffcfbc62192b28597b705653496c9a7 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 29 Jul 2016 20:03:54 -0400 Subject: [PATCH 127/204] Move bit about keywords to the intro part of this chapter --- src/ch04-00-common-programming-concepts-in-rust.md | 13 +++++++++++++ src/ch04-01-anatomy-of-a-rust-program.md | 11 ----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/ch04-00-common-programming-concepts-in-rust.md b/src/ch04-00-common-programming-concepts-in-rust.md index e4c67f5427..99ed50701f 100644 --- a/src/ch04-00-common-programming-concepts-in-rust.md +++ b/src/ch04-00-common-programming-concepts-in-rust.md @@ -9,3 +9,16 @@ Rust’s particular syntax and conventions concerning these common concepts. Specifically, we’ll be talking about variable bindings, basic types, functions, comments, and control flow. These foundations will be in every Rust program, and learning them early will give you a strong core to start from. + +PROD: START BOX + +Keep in mind as we get into variables and functions that the Rust language has +a set of *keywords* that have been reserved for use by the language only, much +like other languages do. This means you cannot use these words as names of +variables or functions, for example. Most of these have special meaning and we +will be using them to do various things in our Rust programs; a few have no +current functionality associated but have been reserved for functionality that +might be in the Rust language in the future. You can find a list of the +keywords in Appendix XX. + +PROD: END BOX diff --git a/src/ch04-01-anatomy-of-a-rust-program.md b/src/ch04-01-anatomy-of-a-rust-program.md index 0b61d6b26b..7183add1cb 100644 --- a/src/ch04-01-anatomy-of-a-rust-program.md +++ b/src/ch04-01-anatomy-of-a-rust-program.md @@ -5,17 +5,6 @@ data, but to create this data, you first have to create a program. Here, we'll write some code that demonstrates how to begin a Rust program, how to bind a variable, and how to print text to the terminal. -PROD: START BOX - -Keep in mind that the Rust language has a set of *keywords* that have -been reserved for use by the language only. This means you cannot use these -words as names of variables or functions, for example. Most of these have -special meaning and we will be using them to do various things in our Rust -programs; a few have no current functionality associated but have been reserved -for functionality that might be in the Rust language in the future. You can find a list of the keywords in Appendix XX. - -PROD: END BOX - ### A Simple Program that Binds a Variable Let’s start with a short example that binds a value to a variable and then uses From 08154ad6bcdb4d813364953d874a39402ae41d6d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 29 Jul 2016 20:16:27 -0400 Subject: [PATCH 128/204] Remove anatomy of a rust program section that's duplicated elsewhere Except the crab pincers. Move those to the first discussion of println!() :) --- src/SUMMARY.md | 1 - src/ch02-00-guessing-game-tutorial.md | 11 +- src/ch04-01-anatomy-of-a-rust-program.md | 163 ----------------------- 3 files changed, 7 insertions(+), 168 deletions(-) delete mode 100644 src/ch04-01-anatomy-of-a-rust-program.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 759103ffb7..840330bda9 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -12,7 +12,6 @@ - [Slices](ch03-03-slices.md) - [Common Programming Concepts in Rust](ch04-00-common-programming-concepts-in-rust.md) - - [Anatomy of a Rust Program](ch04-01-anatomy-of-a-rust-program.md) - [Variable Bindings in Detail](ch04-02-variable-bindings-in-detail.md) - [Data Types](ch04-03-data-types.md) - [How Functions Work](ch04-04-how-functions-work.md) diff --git a/src/ch02-00-guessing-game-tutorial.md b/src/ch02-00-guessing-game-tutorial.md index 80d3c72780..f419c7df93 100644 --- a/src/ch02-00-guessing-game-tutorial.md +++ b/src/ch02-00-guessing-game-tutorial.md @@ -287,9 +287,10 @@ brace: } ``` -This prints out the string we saved our input in. The `{}`s are a placeholder, -and we pass `guess` as an argument to the macro. If we had multiple `{}`s, we -would pass multiple arguments: +This prints out the string we saved our input in. The `{}`s are a placeholder: +think of `{}` as little crab pincers, holding a value in place. The first `{}` +holds the first value after the format string, the second set holds the second +value, and so on. Printing out multiple values in one call to `println!()` would then look like this: ```rust let x = 5; @@ -298,7 +299,9 @@ let y = 10; println!("x and y: {} and {}", x, y); ``` -Anyway, that’s the tour. We can run what we have with `cargo run`: +Which would print out "x and y: 5 and 10". + +Anyway, back to our guessing game. We can run what we have with `cargo run`: ```bash $ cargo run diff --git a/src/ch04-01-anatomy-of-a-rust-program.md b/src/ch04-01-anatomy-of-a-rust-program.md deleted file mode 100644 index 7183add1cb..0000000000 --- a/src/ch04-01-anatomy-of-a-rust-program.md +++ /dev/null @@ -1,163 +0,0 @@ -## Anatomy of a Rust Program - -The foundation of virtually every program is the ability to store and modify -data, but to create this data, you first have to create a program. Here, we'll -write some code that demonstrates how to begin a Rust program, how to bind a -variable, and how to print text to the terminal. - -### A Simple Program that Binds a Variable - -Let’s start with a short example that binds a value to a variable and then uses -that in a sentence that we'll print to the screen. First, we’ll generate a new -project with Cargo. Open a terminal, and navigate to the directory you want to -store your projects in. From there, generate a new project: - -```bash -$ cargo new --bin bindings -$ cd bindings -``` - -This creates a new project called `bindings` and sets up our *Cargo.toml* and -*src/main.rs* files. As we saw in Chapter XX, Cargo will generate these files -and create a little "hello world" program like this: - -```rust -fn main() { - println!("Hello, world!"); -} -``` - -Open *src/main.rs* and replace its code with the following: - -```rust -fn main() { - let x = 5; - - println!("The value of x is: {}", x); -} -``` - -This is the full program for our example. Enter the `run` command now to to see -it working: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -``` - -If you get an error instead of this output, double check that you've copied the -program exactly as written, and then try again. Now let’s break this program -down, line by line. - -#### Starting a Program with the main() Function - -Many Rust programs will contain the same function that our example program does: - -```rust,ignore -fn main() { -``` - -The `main()` function is the entry point of every executable Rust program. It -doesn’t have to be at the very beginning of our source code, but it will be the -first bit of code that runs when we execute our program. We’ll talk more about -functions in a later section, but for now, just know that `main()` is -where our program begins. The opening curly brace (`{`) indicates the start of -the function’s body. - -#### Binding a Variable with `let` - -Inside the function body, we added the following: - -```rust,ignore -let x = 5; -``` - -This is a `let` statement, and it binds the value `5` to the variable `x`. -`let` statements take the following form: - -```text -let PATTERN = EXPRESSION; -``` - -A `let` statement first evaluates the `EXPRESSION` and then binds the resulting -value to `PATTERN` to give us a variable to use later in the program. -*Patterns* are part of the *pattern matching* feature of Rust, which will be -covered in more detail in Chapter XX. For now, know that a pattern made of one -name is a simple pattern that matches the value of the entire expression. -Notice the semicolon at the end of the statement, too. As in many other -programming languages, statements in Rust must end with a semicolon. - -In this simple example, the expression already is a value, but we could achieve -the same result like this: - -```rust -let x = 2 + 3; -``` - -The expression `2 + 3` would evaluate to `5`, which would in turn be stored in -the `x` variable binding. - -#### Printing to the Screen with a Macro - -The next line of our program is: - -```rust,ignore - println!("The value of x is: {}", x); -``` - -The `println!` command is a *macro* that prints the text passed to it to the -screen. Macros are indicated with the `!` character at the end of their name. -In Chapter XX, you'll learn more about the details of macros and how to -write macros yourself, but for now we'll just be using macros provided by the -standard Rust library. - -Macros can add new syntax to the language to enable convenient code reuse. -Using a macro may look similar to calling a function, but they do have -different capabilities. The `!` is a reminder that calling a macro may look -slightly unusual. For example, the "Hello, world!" program that `cargo new` -generated for us called the `println!` macro with one argument (the string -`"Hello, world!"`). Here, we are calling it with two arguments (the string -`"The value of x is: {}"` and `x`). Functions in Rust must always be called -with the same number of arguments that their definition specifies, but macros -have different rules that allow them to take different numbers of arguments. - -The `println!` macro only requires one argument: a format string. You can add -optional arguments inside this format string by using the special text `{}`. -Each instance of `{}` corresponds to an additional argument. Here’s an example: - -```rust -let x = 2 + 3; -let y = x + 5; - -println!("The value of x is {}, and the value of y is {}", x, y); -``` - -If you were to run a program containing these statements, it would print the -following: - -```text -The value of x is 5, and the value of y is 10 -``` - -Think of `{}` as little crab pincers, holding a value in place. The first `{}` -holds the first value after the format string, the second set holds the second -value, and so on. - -After the `println!` macro, we match the opening curly brace that declared the -`main()` function with a closing curly brace to declare the end of the function: - -```rust,ignore -} -``` - -And as we saw earlier, when we run the program, our output is: - -```text -The value of x is: 5 -``` - -With this simple program, you've created your first variable and used your -first Rust macro. That makes you a Rust programmer. Welcome! Now that you've -seen the basics, let's explore variable bindings further. From f915f9af4b8757d35fc738a9354d001ee854465d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 29 Jul 2016 20:17:42 -0400 Subject: [PATCH 129/204] Chapter 1 can have the "Anatomy of a Rust Program" title back --- src/ch01-02-hello-world.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch01-02-hello-world.md b/src/ch01-02-hello-world.md index 874867dac1..bac171affc 100644 --- a/src/ch01-02-hello-world.md +++ b/src/ch01-02-hello-world.md @@ -56,7 +56,7 @@ system, you should see the string `Hello, world!` print to the terminal. If you did, then congratulations! You've officially written a Rust program. That makes you a Rust programmer! Welcome. -## Hello, World Explained +## Anatomy of a Rust Program Now, let’s go over what just happened in your "Hello, world!" program in detail. Here's the first piece of the puzzle: From 9213bbc9d023b6110f2160be8c1f579a84e09824 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 29 Jul 2016 20:28:11 -0400 Subject: [PATCH 130/204] Simplify slice examples by using byte literal. --- src/ch04-04-slices.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/ch04-04-slices.md b/src/ch04-04-slices.md index 3d028635d6..0d0e7459ba 100644 --- a/src/ch04-04-slices.md +++ b/src/ch04-04-slices.md @@ -25,7 +25,7 @@ fn first_word(s: &String) -> usize { let bytes = s.as_bytes(); for (i, &byte) in bytes.iter().enumerate() { - if byte == 32 { + if byte == b' ' { return i; } } @@ -55,9 +55,7 @@ fn first_word(s: &String) -> usize { // So we match against the tuple with i for the index, and &byte for // the byte itself. for (i, &byte) in bytes.iter().enumerate() { - - // 32 is the value of a space in UTF-8 - if byte == 32 { + if byte == b' ' { // We found a space! Return this position. return i; @@ -80,7 +78,7 @@ that it will still be valid in the future. Consider this: # let bytes = s.as_bytes(); # # for (i, &byte) in bytes.iter().enumerate() { -# if byte == 32 { +# if byte == b' ' { # return i; # } # } @@ -166,7 +164,7 @@ fn first_word(s: &String) -> &str { let bytes = s.as_bytes(); for (i, &byte) in bytes.iter().enumerate() { - if byte == 32 { + if byte == b' ' { return &s[0..i]; } } @@ -193,7 +191,7 @@ the slice version of `first_word()` will throw an error: # let bytes = s.as_bytes(); # # for (i, &byte) in bytes.iter().enumerate() { -# if byte == 32 { +# if byte == b' ' { # return &s[0..i]; # } # } @@ -273,7 +271,7 @@ with no loss of functionality: # let bytes = s.as_bytes(); # # for (i, &byte) in bytes.iter().enumerate() { -# if byte == 32 { +# if byte == b' ' { # return &s[0..i]; # } # } From 86c9daef412a1cf6ed4474c02545fb6f7cb51059 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Fri, 29 Jul 2016 21:37:35 -0400 Subject: [PATCH 131/204] Change variable bindings section to mostly be about mutability Leave a bit about shadowing and how it relates to mutability. Change the error explanation box to be about the mutability error. I have some placeholders in here that I will resolve tomorrow. --- src/SUMMARY.md | 2 +- src/ch02-00-guessing-game-tutorial.md | 3 +- ...h04-01-variable-bindings-and-mutability.md | 174 +++++++ src/ch04-02-variable-bindings-in-detail.md | 454 ------------------ 4 files changed, 176 insertions(+), 457 deletions(-) create mode 100644 src/ch04-01-variable-bindings-and-mutability.md delete mode 100644 src/ch04-02-variable-bindings-in-detail.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 840330bda9..1013160eba 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -12,7 +12,7 @@ - [Slices](ch03-03-slices.md) - [Common Programming Concepts in Rust](ch04-00-common-programming-concepts-in-rust.md) - - [Variable Bindings in Detail](ch04-02-variable-bindings-in-detail.md) + - [Variable Bindings and Mutability](ch04-01-variable-bindings-and-mutability.md) - [Data Types](ch04-03-data-types.md) - [How Functions Work](ch04-04-how-functions-work.md) - [Comments](ch04-05-comments.md) diff --git a/src/ch02-00-guessing-game-tutorial.md b/src/ch02-00-guessing-game-tutorial.md index f419c7df93..81d87794b2 100644 --- a/src/ch02-00-guessing-game-tutorial.md +++ b/src/ch02-00-guessing-game-tutorial.md @@ -133,8 +133,7 @@ let mut guess = String::new(); Now we’re getting interesting! There’s a lot going on in this little line. The first thing to notice is that this is a let statement, which is -used to create ‘variable bindings’. Variable bindings will be covered in more -detail in Chapter XX. Here's an example: +used to create what are called ‘variable bindings’. Here's an example: ```rust,ignore let foo = bar; diff --git a/src/ch04-01-variable-bindings-and-mutability.md b/src/ch04-01-variable-bindings-and-mutability.md new file mode 100644 index 0000000000..0eea614a83 --- /dev/null +++ b/src/ch04-01-variable-bindings-and-mutability.md @@ -0,0 +1,174 @@ +## Variable Bindings and Mutability + +We mentioned in Chapter XX that by default, variable bindings are *immutable*. +This is one of many nudges that Rust's design has to encourage us to write our +code to get the most of the safety and easy concurrency that Rust has to offer. +We still have the option to make our bindings mutable, though. Let's explore +how and why Rust encourages us to favor immutability, and why we might want to +opt out of that. + +Variable bindings being immutable means that once a value is bound, you can't +change that value. To illustrate this, let's generate a new project with Cargo. +Open a terminal, and navigate to the directory you want to store your projects +in. From there, run these commands: + +```bash +$ cargo new --bin bindings +$ cd bindings +``` + +Then open *src/main.rs* and replace its code with the following: + +```rust,ignore +fn main() { + let x = 5; + x = 6; + println!("The value of x is: {}", x); +} +``` + +Save and run the program using `cargo run`, and you should receive an error +message, as in this output: + +```bash +$ cargo run + Compiling bindings v0.0.1 (file:///projects/bindings) +error: re-assignment of immutable variable `x` [--explain E0384] + --> src/main.rs:3:5 +3 |> x = 6; + |> ^^^^^ +note: prior assignment occurs here + --> src/main.rs:2:9 +2 |> let x = 5; + |> ^ +``` + +This is our first example of the compiler helping us find an error in our +program! Compiler errors can be frustrating. Keep in mind that they only mean +your program isn't safely doing what you want it to do yet; they do _not_ mean +that you're not a good programmer! Experienced Rustaceans still get compiler +errors. Try to keep in mind that the Rust compiler is trying to help your +program be the very best. + +PROD: START BOX +######Extended Error Explanations + +Now that you've seen an example of a Rust error, let's look at one particularly +useful aspect of errors. Rust encourages you to seek further information on the +kind of error you've received with output like this: + +```bash +error: re-assignment of immutable variable `x` [--explain E0384] +``` + +This tells us that if we pass the `--explain` flag to `rustc` with the provided +error code, we can see an extended explanation which will try to explain common +causes of and solutions to that kind of error. Not every error has a longer +explanation, but many do. Here’s the explanation for the `E0384` error we +received: + +````bash +$ rustc --explain E0384 +This error occurs when an attempt is made to reassign an immutable variable. +For example: + +``` +fn main(){ + let x = 3; + x = 5; // error, reassignment of immutable variable +} +``` + +By default, variables in Rust are immutable. To fix this error, add the keyword +`mut` after the keyword `let` when declaring the variable. For example: + +``` +fn main(){ + let mut x = 3; + x = 5; +} +``` +```` + +These explanations can really help if you’re stuck on an error, so don't +hesitate to look up the error code. The compiler is your friend, and it's there +to help. + +PROD: END BOX + +The error includes the message `re-assigment of immutable variable` because the +program tried to assign a second value to the `x` variable. + + +******* insert *why* immutability is desirable here ********* + + +But bindings are +immutable only by default; you can make them mutable by adding `mut` in front +of the variable name. For example, change the program you just wrote to the +following: + +```rust +fn main() { + let mut x = 5; + println!("The value of x is: {}", x); + x = 6; + println!("The value of x is: {}", x); +} +``` + +Running this, we get: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) + Running `target/debug/bindings` +The value of x is: 5 +The value of x is: 6 +``` + +Using `mut`, we change the value that `x` binds to from `5` to `6`. + + +******* insert *why* you might want to use mutability here ********* + + + + +One final thing about bindings: they can *shadow* previous bindings. Shadowing +is what happens when you declare two bindings with the same name. We say that +the first binding is ‘shadowed’ by the second, which means that the second +binding's value is what you will see when you use the variable after the second +binding. This can be useful if you’d like to perform a few transformations on a +value, but still leave the binding immutable. For example: + +```rust +fn main() { + let x = 5; + + let x = x + 1; + + let x = x * 2; + + println!("The value of x is: {}", x); +} +``` + +This program first binds `x` to a value of `5`. Then, it shadows `x` by saying +`let x =` again, taking the original value and adding `1` so that the value of +`x` is then `6`. The third `let` statement also shadows `x`, taking the +previous value and multiplying it by `2` to give `x` a final value of `12`. If +you run this, it will output: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) + Running `target/debug/bindings` +The value of x is: 12 +``` + +Shadowing is useful because it lets us modify `x` without having to make the +variable mutable. This means the compiler will still keep us from accidentally +trying to mutate `x` directly later. + +Now let's look at some of the types of values that we can bind variables to. diff --git a/src/ch04-02-variable-bindings-in-detail.md b/src/ch04-02-variable-bindings-in-detail.md deleted file mode 100644 index 759583cdd6..0000000000 --- a/src/ch04-02-variable-bindings-in-detail.md +++ /dev/null @@ -1,454 +0,0 @@ -## Variable Bindings in Detail - -So far, we’ve created the simplest kind of variable binding, but the `let` -statement has some more tricks up its sleeve. Now we'll look at doing more -complex things: creating multiple bindings at once, creating mutating bindings, -understanding shadowing, and more. - -### Creating Multiple Bindings - -The previous example program just bound one variable, but it's also possible to -create multiple variable bindings in one go. Let’s try a more complex example, -creating two variable bindings at once. Change your example program to this: - -```rust -fn main() { - let (x, y) = (5, 6); - - println!("The value of x is: {}", x); - println!("The value of y is: {}", y); -} -``` - -And enter `cargo run` to run it: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -The value of y is: 6 -``` - -We’ve created two bindings with one `let` statement! The `let` statement binds -the values in `(5, 6)` to the corresponding patterns of `(x, y)`. The first -value `5` binds to the first part of the pattern, `x`, and the second value `6` -binds to `y`. We could alternatively have used two `let` statements to the same -effect, as follows: - -```rust -fn main() { - let x = 5; - let y = 6; -} -``` - -In simple cases like this where we are only binding two variables, two `let` -statements may be clearer in the code, but when you're creating many multiple -bindings, it's useful to be able to do so all at once. Deciding which technique -to use is mostly a judgement call, and as you become more proficient in Rust, -you’ll be able to figure out which style is better in each case. - -### Delayed Initialization - -The examples so far have all provided bindings with an initial value, but that -isn't always necessary. Rather, we can assign a value for the binding later, -after the `let` statement. To try this out, write the following program: - -```rust -fn main() { - let x; - x = 5; - println!("The value of x is: {}", x); -} -``` - -And enter `cargo run` to run it: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -``` - -As you can see, this works just like the previous program in which we assigned -an initial value. - -This raises an interesting question: what happens if we try to print out a -binding before we declare a value? Let's find out. Modify your code to look -like the following: - -```rust,ignore -fn main() { - let x; - println!("The value of x is: {}", x); - x = 5; -} -``` - -When you enter `cargo run` to run this code, you should see output like this -after the command: - -```bash - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x` [E0381] -src/main.rs:4 println!("The value of x is: {}", x); - ^ -:2:25: 2:56 note: in this expansion of format_args! -:3:1: 3:54 note: in this expansion of print! (defined in ) -src/main.rs:4:5: 4:42 note: in this expansion of println! (defined in ) -src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed explanation -error: aborting due to previous error -Could not compile `bindings`. - -To learn more, run the command again with --verbose. -``` - -There's been an error! The compiler won’t let us write a program like this, and -instead it requests that you assign a value to the variable `x`. This is our -first example of the compiler helping us find an error in our program. -Different programming languages have different ways of approaching this -problem. Some languages will always initialize values with some sort of -default. Other languages leave the value uninitialized and make no promises -about what happens if you try to use something before initialization. Rust -responds with an error to prod the programmer to declare the value they want. -We must initialize any variable before we can use it. - -PROD: START BOX -######Extended Error Explanations - -Now that you've seen an example of a Rust error, I want to point out one -particularly useful aspect of errors. Rust encourages you to seek further -information on the kind of error you've received with output like this: - -```bash -src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed explanation -``` - -This tells us that if we pass the `--explain` flag to `rustc` with the provided -error code, we can see an extended explanation which will try to explain common -causes of and solutions to that kind of error. Not every error has a longer -explanation, but many do. Here’s the explanation for the `E0381` error we -received previously: - -```bash -$ rustc --explain E0381 -It is not allowed to use or capture an uninitialized variable. For example: - -fn main() { - let x: i32; - - let y = x; // error, use of possibly uninitialized variable - -To fix this, ensure that any declared variables are initialized before being -used. -``` - -These explanations can really help if you’re stuck on an error, so don't -hesitate to look up the error code. The compiler is your friend, and it's there -to help. - -PROD: END BOX - -### Mutable bindings - -By default, variable bindings are *immutable*, meaning that once a value is -bound, you can't change that value. Try writing the following sample program to -illustrate this: - -```rust,ignore -fn main() { - let x = 5; - x = 6; - println!("The value of x is: {}", x); -} -``` - -Save and run the program, and you should receive another error message, as in -this output: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:4:5: 4:10 error: re-assignment of immutable variable `x` [E0384] -src/main.rs:4 x = 6; - ^~~~~ -src/main.rs:4:5: 4:10 help: run `rustc --explain E0384` to see a detailed explanation -src/main.rs:2:9: 2:10 note: prior assignment occurs here -src/main.rs:2 let x = 5; - ^ -``` - -The error includes the message `re-assigment of immutable variable` because the -program tried to assign a second value to the `x` variable. But bindings are -immutable only by default; you can make them mutable by adding `mut` in front -of the variable name. For example, change the program you just wrote to the -following: - -```rust -fn main() { - let mut x = 5; - println!("The value of x is: {}", x); - x = 6; - println!("The value of x is: {}", x); -} -``` - -Running this, we get: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -The value of x is: 6 -``` - -Using `mut`, we change the value that `x` binds to from `5` to `6`. - -### Variable Binding Scope - -As we discussed in the ownership section of Chapter XX, variable bindings are -only valid as long as they are *in scope*. That scope begins at the point where -the binding is declared and ends with the curly brace that closes the block of -code containing that binding. We cannot access bindings "before they come into -scope" or "after they go out of scope." Here’s an example to illustrate this: - -```rust -fn main() { - println!("x is not yet in scope. Try to print x in this statement to see the compiler error!"); - - let x = 5; - - println!("x is now in scope and its value is {}.", x); - - println!("In real code, we’d now do a bunch of work."); - - println!("x will go out of scope now! The next curly brace is ending the main function."); -} -``` - -The variable binding for `x` goes out of scope with the last curly brace in the -`main()` function. - -This example only has one scope, though. In Rust, it's possible to create -arbitrary scopes within a scope by placing code within another pair of curly -braces. For example: - -```rust -fn main() { - println!("x is not yet in scope"); - - let x = 5; - - println!("x is now in scope and its value is {}.", x); - println!("y is not yet in scope. Try to print y in this statement to see the compiler error!"); - println!("Let’s start a new scope!"); - - { - println!("y is still not yet in scope..."); - let y = 8; - - println!("NOW y is in scope and its value is {}", y); - println!("x is also still in scope with value {}", x); - - println!("y will go out of scope now!"); - println!("The next curly brace is ending the scope we started."); - } - - println!("x is still in scope: {}", x); - println!("y is now out of scope and is not usable. Try using it here!"); - - println!("x will go out of scope now! The next curly brace is ending the main function."); -} -``` - -The `y` variable is only in scope in the section of the code that's between the -nested pair of curly braces, whereas `x` is in scope from the `let` statement -that binds it until the final curly brace. - -### Shadowing Earlier Bindings - -One final thing about bindings: they can *shadow* previous bindings. Shadowing -is what happens when you declare two bindings with the same name. We say that -the first binding is ‘shadowed’ by the second, which means that the second -binding's value is what you will see when you use the variable after the second -binding. This can be useful if you’d like to perform a few transformations on a -value, but still leave the binding immutable. For example: - -```rust -fn main() { - let x = 5; - - let x = x + 1; - - let x = x * 2; - - println!("The value of x is: {}", x); -} -``` - -This program first binds `x` to a value of `5`. Then, it shadows `x` by saying -`let x =` again, taking the original value and adding `1` so that the value of -`x` is then `6`. The third `let` statement also shadows `x`, taking the -previous value and multiplying it by `2` to give `x` a final value of `12`. If -you run this, it will output: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 12 -``` - -Shadowing is useful because it lets us modify `x` without having to make the -variable mutable. This means the compiler will still keep us from accidentally -trying to mutate `x` directly later. For example, say after calculating `12` we -don’t want `x` to be modified again; if we write the program in a mutable -style, like this: - -```rust -fn main() { - let mut x = 5; - - x = x + 1; - x = x * 2; - - println!("The value of x is: {}", x); - - x = 15; - - println!("The value of x is: {}", x); -} -``` - -Rust is happy to let us mutate `x` again, to `15`. A similar program using the -default immutable style, however, will prevent us from mutating `x`. Here's an -example: - -```rust,ignore -fn main() { - let x = 5; - let x = x + 1; - let x = x * 2; - - println!("The value of x is: {}", x); - - x = 15; - - println!("The value of x is: {}", x); -} -``` - -If we try to compile this, we get an error: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:8:5: 8:11 error: re-assignment of immutable variable `x` [E0384] -src/main.rs:8 x = 15; - ^~~~~~ -src/main.rs:8:5: 8:11 help: run `rustc --explain E0384` to see a detailed explanation -src/main.rs:4:9: 4:10 note: prior assignment occurs here -src/main.rs:4 let x = x * 2; - ^ -error: aborting due to previous error -Could not compile `bindings`. -``` - -Since we don't want the binding to be mutable, this is exactly what should -happen. - -#### Shadowing Over Bindings - -You can also shadow bindings over one another, without re-using the initial -binding in the value. Here's how that looks: - -```rust -fn main() { - let x = 5; - let x = 6; - - println!("The value of x is: {}", x); -} -``` - -Running this sample program, we can see the shadowing in action: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default -src/main.rs:2 let x = 5; - ^ - Running `target/debug/bindings` -The value of x is: 6 -``` - -Rust gives the value of `x` as `6`, which is the value from the *second* `let` -statement. There are a few interesting things in this output. First, Rust -will compile and run the program without issue. This is because we haven't -mutated the value; instead, we declared a _new_ binding that is _also_ named -`x`, and gave it a new value. - -The other interesting thing in this output is this warning line: - -```bash -src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default -``` - -Rust is pointing out that we shadowed `x`, but never used the initial value. -Doing so isn’t _wrong_, but Rust is checking whether this is intentional and -not just a mistake. In this case, the compiler issues a warning, but still -compiles our program. A warning like this is called a *lint*, which is an old -term for the bits of fluff and fibers in sheep’s wool that you wouldn't want to -put in cloth. - -Similarly, this lint is telling us that we may have an extra bit of code (the -statement `let x = 5`) that we don’t need. Even though our program works just -fine, listening to these warnings and fixing the problems they point out is -worthwhile, as they can be signs of a larger problem. In this case, we may not -have realized that we were shadowing `x`, when we meant to, say, define a new -variable with a different name. - -Shadowing can take some time to get used to, but it’s very powerful and works -well with immutability. - -#### Shadowing and Scopes - -Like any binding, a binding that shadows another binding becomes invalid at the -end of a scope. Here’s an example program to illustrate this: - -```rust -fn main() { - let x = 5; - println!("Before shadowing, x is: {}", x); - - { - let x = 6; - println!("Now that x is shadowed, x is: {}", x); - } - - println!("After shadowing, x is: {}", x); -} -``` - -This code first creates the `x` variable and prints `x` to the terminal. Then, -inside a new scope, it creates a new binding for `x` with a new value and -prints that value. When the arbitrary scope ends, `x` is printed once more. If -we run this example, we can see the shadow appear and disappear in the output: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -Before shadowing, x is: 5 -Now that x is shadowed, x is: 6 -After shadowing, x is: 5 -``` - -In this case, the binding value reverts to the original value once the shadow -binding goes out of scope. - -Now let's look at some of the types of values that we can bind variables to. From da86f50ab827eef2130fc7b8aa1eae947ab78aa3 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 29 Jul 2016 22:53:54 -0400 Subject: [PATCH 132/204] Don't use UFCS before it gets introduced. It's not introduced until later in this page. --- src/ch05-02-method-syntax.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ch05-02-method-syntax.md b/src/ch05-02-method-syntax.md index 89e8ba354e..ef4cb6ac6a 100644 --- a/src/ch05-02-method-syntax.md +++ b/src/ch05-02-method-syntax.md @@ -189,7 +189,7 @@ reference. Yet, we needed a `&` for `p2` but not `p1`. What gives? This feature is called ‘automatic referencing’, and calling methods is one of the few places in Rust that has behavior like this. Here’s how it works: when you call a method with `self.(`, Rust will automatically add in `&`s -or `&mut`s to match the signature. In other words, these three are the same: +or `&mut`s to match the signature. In other words, these are the same: ```rust # #[derive(Debug,Copy,Clone)] @@ -210,7 +210,6 @@ or `&mut`s to match the signature. In other words, these three are the same: # let p2 = Point { x: 5.0, y: 6.5 }; p1.distance(&p2); (&p1).distance(&p2); -Point::distance(&p1, &p2); ``` The first one looks much, much cleaner. Here’s another example: From 4867721c8cd503e1cd359c1cee2dc9942c2e4e25 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 29 Jul 2016 23:11:30 -0400 Subject: [PATCH 133/204] Indicate system variable is code-like. --- src/ch01-02-installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch01-02-installation.md b/src/ch01-02-installation.md index 11056e4f82..cba8d82ca7 100644 --- a/src/ch01-02-installation.md +++ b/src/ch01-02-installation.md @@ -56,7 +56,7 @@ You should see the version number, commit hash, and commit date. If you do, Rust has been installed successfully! Congrats! -If you don't and you're on Windows, check that Rust is in your %PATH% system +If you don't and you're on Windows, check that Rust is in your `%PATH%` system variable. If it isn't, run the installer again, select "Change" on the "Change, repair, or remove installation" page and ensure "Add to PATH" is checked. From 2e18fde173a9d8d9d4637e1debfb5d8c9b44fc92 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 14:04:31 -0400 Subject: [PATCH 134/204] Explain why mutability is important, when to use. Flow into shadowing --- ...h04-01-variable-bindings-and-mutability.md | 53 ++++++++++++------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/ch04-01-variable-bindings-and-mutability.md b/src/ch04-01-variable-bindings-and-mutability.md index 0eea614a83..0649b8eaa6 100644 --- a/src/ch04-01-variable-bindings-and-mutability.md +++ b/src/ch04-01-variable-bindings-and-mutability.md @@ -22,6 +22,7 @@ Then open *src/main.rs* and replace its code with the following: ```rust,ignore fn main() { let x = 5; + println!("The value of x is: {}", x); x = 6; println!("The value of x is: {}", x); } @@ -34,7 +35,7 @@ message, as in this output: $ cargo run Compiling bindings v0.0.1 (file:///projects/bindings) error: re-assignment of immutable variable `x` [--explain E0384] - --> src/main.rs:3:5 + --> src/main.rs:4:5 3 |> x = 6; |> ^^^^^ note: prior assignment occurs here @@ -99,14 +100,26 @@ PROD: END BOX The error includes the message `re-assigment of immutable variable` because the program tried to assign a second value to the `x` variable. +Getting compile-time errors when your code attempts to change a value that it +previously said was immutable is important because this very situation can lead +to bugs. If one part of your code operates on an assumption that a value it's +operating on will never change, and another part of your code changes that +value, it's possible that the first code won't do what it was designed to do. +Especially when the second piece of code only changes the value _sometimes_, +this cause of bugs can be difficult to track down after the fact. -******* insert *why* immutability is desirable here ********* +In Rust, our code can know that a value our code assumes won't change really +won't change, because the compiler is enforcing that guarantee for us. When +reading and writing code, we don't have to keep track in our head how and where +a value might change. This can make code easier to reason about. +Mutability is really useful, though! Bindings are immutable only by default; +you can make them mutable by adding `mut` in front of the variable name. In +addition to telling the compiler it should allow this value to be changed, it +conveys intent to future readers of the code and says that other parts of the +code will be changing this value. -But bindings are -immutable only by default; you can make them mutable by adding `mut` in front -of the variable name. For example, change the program you just wrote to the -following: +For example, change the program you just wrote to the following: ```rust fn main() { @@ -127,20 +140,22 @@ The value of x is: 5 The value of x is: 6 ``` -Using `mut`, we change the value that `x` binds to from `5` to `6`. - - -******* insert *why* you might want to use mutability here ********* - - +Using `mut`, we are allowed to change the value that `x` binds to from `5` to +`6`. You might want to make a binding mutable because it makes the code easier +to understand than an implementation that only uses immutable bindings. In +cases where you're using large data structures, mutating an instance in place +may be faster than copying and returning newly allocated instances. It all +depends on the tradeoffs you want to make in your situation. +### Shadowing -One final thing about bindings: they can *shadow* previous bindings. Shadowing -is what happens when you declare two bindings with the same name. We say that -the first binding is ‘shadowed’ by the second, which means that the second -binding's value is what you will see when you use the variable after the second -binding. This can be useful if you’d like to perform a few transformations on a -value, but still leave the binding immutable. For example: +As we saw in the guessing game tutorial, we can declare new bindings with the +same name as a previous binding, and the new binding *shadows* the previous +binding. We say that the first binding is ‘shadowed’ by the second, which means +that the second binding's value is what you will see when you use the variable +after the second binding. This can be useful if you’d like to perform a few +transformations on a value, but have the binding be immutable after those +transformations have been completed. For example: ```rust fn main() { @@ -168,7 +183,7 @@ The value of x is: 12 ``` Shadowing is useful because it lets us modify `x` without having to make the -variable mutable. This means the compiler will still keep us from accidentally +binding mutable. This means the compiler will still keep us from accidentally trying to mutate `x` directly later. Now let's look at some of the types of values that we can bind variables to. From fb56f123f3db2ecedbb67f6826c690089198d590 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 14:11:14 -0400 Subject: [PATCH 135/204] Move Patterns to be its own top-level chapter --- src/SUMMARY.md | 3 +- src/ch03-02-variable-bindings.md | 116 ------------------ src/{ch06-05-patterns.md => chXX-patterns.md} | 106 +++++++++++++++- 3 files changed, 103 insertions(+), 122 deletions(-) rename src/{ch06-05-patterns.md => chXX-patterns.md} (62%) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index e5d428b065..864c33f8a5 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -30,7 +30,6 @@ - [Option](ch06-02-option.md) - [Match](ch06-03-match.md) - [if let](ch06-04-if-let.md) - - [Patterns](ch06-05-patterns.md) - [Crates & Modules]() @@ -49,6 +48,8 @@ - [Iterators]() +- [Patterns](chXX-patterns.md) + - [I/O]() - [`Read` & `Write`]() - [`std::fs`]() diff --git a/src/ch03-02-variable-bindings.md b/src/ch03-02-variable-bindings.md index d9b8d0fc06..9e6f11b19a 100644 --- a/src/ch03-02-variable-bindings.md +++ b/src/ch03-02-variable-bindings.md @@ -61,25 +61,6 @@ start of the function’s body. This is our first ‘variable binding’, which we create with a ‘`let` statement’. -This `let` statement has this form: - -```text -let NAME = EXPRESSION; -``` - -A `let` statement first evaluates the `EXPRESSION`, and then binds the -resulting value to `NAME` so that it can be referred to later in the program. -In our simple example, the expression was already a value, 5, but we could -achieve the same effect with: - -```rust -let x = 2 + 3; -``` - -In general, `let` statements work with patterns; a name is a particularly -humble form of pattern. Patterns are a big part of Rust, we’ll see more complex -and powerful patterns as we go along. - Before we do that, though, let’s finish investigating this example. Here’s the next line: @@ -125,103 +106,6 @@ The value of x is: 5 We assign `5` to a binding, `x`, and then print it to the screen with `println!`. -## Multiple binding - -Let’s try a more complex pattern. Change our example program to this: - -```rust -fn main() { - let (x, y) = (5, 6); - - println!("The value of x is: {}", x); - println!("The value of y is: {}", y); -} -``` - -And run it with `cargo run`: - -```text -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -The value of y is: 6 -``` - -We’ve created two bindings with one `let`! Here’s our pattern: - -```text -(x, y) -``` - -And here’s the value: - -```text -(5, 6) -``` - -As you can see, the two line up visually, and so `let` binds `5` to `x` and `6` -to `y`. We could have used two `let` statements as well: - -```rust -fn main() { - let x = 5; - let y = 6; -} -``` - -In simple cases like this, two `let`s may be clearer, but in others, creating -multiple bindings at once is nice. As we become more proficient in Rust, we’ll -figure out which style is better, but it’s mostly a judgement call. - -## Type annotations - -You may have noticed that we didn’t declare the type of `x` or `y` in our -previous examples. Rust is a *statically typed* language, which means that at -compile time, we must know the types of all bindings. But annotating every -single binding with a type can feel like busywork, and make code noisy. To -solve this issue, Rust uses ‘type inference’, meaning that it attempts to infer -the types of your bindings. - -The primary way that the type is inferred is by looking at how it is used. -Let’s look at the example again: - -```rust -fn main() { - let x = 5; -} -``` - -When we bind `x` to `5`, the compiler knows that `x` should be a numeric type. -Without any other information, it defaults to `i32`, a thirty-two bit integer -type. We’ll talk more about Rust’s basic types in section 3.3. - -Here’s what a `let` statement with a ‘type annotation’ looks like: - -```rust -fn main() { - let x: i32 = 5; -} -``` - -We can add a colon, followed by the type name. Here’s the structure of a `let` -statement with a type annotation: - -```text -let PATTERN: TYPE = VALUE; -``` - -Note that the colon and the `TYPE` go _after_ the `PATTERN`, not in the pattern -itself. As an example, here’s our more complex pattern with two bindings: - -```rust -fn main() { - let (x, y): (i32, i32) = (5, 6); -} -``` - -Just like we match up the `VALUE` with the `PATTERN`, we match up the `TYPE` -with the `PATTERN`. ## Delayed Initialization diff --git a/src/ch06-05-patterns.md b/src/chXX-patterns.md similarity index 62% rename from src/ch06-05-patterns.md rename to src/chXX-patterns.md index d6964778cf..93c07349f0 100644 --- a/src/ch06-05-patterns.md +++ b/src/chXX-patterns.md @@ -1,9 +1,105 @@ # 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. +We've actually used patterns a few times so far: they're used in `let` +bindings, in function arguments, and in the `match` expression. Patterns have a +lot more abilities than we have demonstrated so far, 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. + +## `let` statements + +A basic `let` statement has this form: + +```text +let PATTERN = EXPRESSION; +``` + +We've seen bindings that have names in the `PATTERN` slot: a name is just a +particularly humble form of pattern. + +## Multiple bindings + +Let’s try a more complex pattern. Change our example program to this: + +```rust +fn main() { + let (x, y) = (5, 6); + + println!("The value of x is: {}", x); + println!("The value of y is: {}", y); +} +``` + +And run it with `cargo run`: + +```text +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) + Running `target/debug/bindings` +The value of x is: 5 +The value of y is: 6 +``` + +We’ve created two bindings with one `let`! Here’s our pattern: + +```text +(x, y) +``` + +And here’s the value: + +```text +(5, 6) +``` + +As you can see, the two line up visually, and so `let` binds `5` to `x` and `6` +to `y`. We could have used two `let` statements as well: + +```rust +fn main() { + let x = 5; + let y = 6; +} +``` + +In simple cases like this, two `let`s may be clearer, but in others, creating +multiple bindings at once is nice. As we become more proficient in Rust, we’ll +figure out which style is better, but it’s mostly a judgement call. + +## Type annotations + +Most of the time, Rust uses ‘type inference’, meaning that it attempts to infer +the types of your bindings rather than you having to declare them explicitly +even though Rust is a statically typed language. Occasionally, Rust won't have +enough information to infer the type of your value, and you will need to add a +type annotation in with the pattern. + +Here’s what a `let` statement with a ‘type annotation’ looks like: + +```rust +fn main() { + let x: i32 = 5; +} +``` + +We can add a colon, followed by the type name. Here’s the structure of a `let` +statement with a type annotation: + +```text +let PATTERN: TYPE = VALUE; +``` + +Note that the colon and the `TYPE` go _after_ the `PATTERN`, not in the pattern +itself. As an example, here’s our more complex pattern with two bindings: + +```rust +fn main() { + let (x, y): (i32, i32) = (5, 6); +} +``` + +Just like we match up the `VALUE` with the `PATTERN`, we match up the `TYPE` +with the `PATTERN`. ## Literals & _ @@ -188,7 +284,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"), From ed5a22ea2424bc755af84a5ee67aa9f4701d6553 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 14:32:45 -0400 Subject: [PATCH 136/204] Remove Patterns subsection; to become a top-level later chapter See https://github.com/rust-lang/book/pull/167 --- src/SUMMARY.md | 3 +- src/{ch06-04-if-let.md => ch06-03-if-let.md} | 0 src/ch06-03-patterns.md | 197 ------------------- 3 files changed, 1 insertion(+), 199 deletions(-) rename src/{ch06-04-if-let.md => ch06-03-if-let.md} (100%) delete mode 100644 src/ch06-03-patterns.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 1013160eba..85a67ae34f 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -25,8 +25,7 @@ - [Enums](ch06-00-enums.md) - [Option](ch06-01-option.md) - [Match](ch06-02-match.md) - - [Patterns](ch06-03-patterns.md) - - [if let](ch06-04-if-let.md) + - [if let](ch06-03-if-let.md) - [MANY MORE CHAPTERS COMING SOON]() diff --git a/src/ch06-04-if-let.md b/src/ch06-03-if-let.md similarity index 100% rename from src/ch06-04-if-let.md rename to src/ch06-03-if-let.md diff --git a/src/ch06-03-patterns.md b/src/ch06-03-patterns.md deleted file mode 100644 index 1337529473..0000000000 --- a/src/ch06-03-patterns.md +++ /dev/null @@ -1,197 +0,0 @@ -# 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 => (), -} -``` - -It’s 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! 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 2863436054628648782ac650baa821d07325b720 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 14:49:15 -0400 Subject: [PATCH 137/204] Move Debug explanation from arrays to structs --- src/ch04-03-data-types.md | 67 ------------------------------ src/ch05-00-structs.md | 86 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 81 insertions(+), 72 deletions(-) diff --git a/src/ch04-03-data-types.md b/src/ch04-03-data-types.md index 5f4ee1dfcd..eff108eec5 100644 --- a/src/ch04-03-data-types.md +++ b/src/ch04-03-data-types.md @@ -309,73 +309,6 @@ length come after the pattern name and a colon. This array has `5` values, which are of the `i32` type. Unlike the values themselves, the type and array length are separated by a semicolon. -#### Using Debug in the println! Macro - -So far, we’ve been printing values using `{}` in a `println!` macro. If we try -that with an array, however, we'll get an error. Say we have the following -program: - -```rust,ignore -fn main() { - let a = [1, 2, 3, 4, 5]; - - println!("a is: {}", a); -} -``` - -This code tries to print the `a` array directly, which may seem innocuous. But -running it produces the following output: - -```bash -$ cargo run - Compiling arrays v0.1.0 (file:///projects/arrays) -src/main.rs:4:25: 4:26 error: the trait bound `[_; 5]: std::fmt::Display` is not satisfied [E0277] -src/main.rs:4 println!("a is: {}", a); - ^ -:2:25: 2:56 note: in this expansion of format_args! -:3:1: 3:54 note: in this expansion of print! (defined in ) -src/main.rs:4:5: 4:28 note: in this expansion of println! (defined in ) -src/main.rs:4:25: 4:26 help: run `rustc --explain E0277` to see a detailed explanation -src/main.rs:4:25: 4:26 note: `[_; 5]` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string -src/main.rs:4:25: 4:26 note: required by `core::fmt::Display::fmt` -error: aborting due to previous error -``` - -Whew! The core of the error is this part: *the trait bound `[_; 5]: -std::fmt::Display` is not satisfied*. We haven’t discussed traits yet, so this -is bound to be confusing! Here’s all we need to know for now: `println!` can do -many kinds of formatting. By default, `{}` implements a kind of formatting -known as `Display`: output intended for direct end-user consumption. The -primitive types we’ve seen so far implement `Display`, as there’s only one way -you’d show a `1` to a user. But with arrays, the output is less clear. Do you -want commas or not? What about the `[]`s? - -More complex types in the standard library do not automatically implement -`Display` formatting. Instead, Rust implements another kind of formatting -intended for the programmer. This formatting type is called `Debug`. To ask -`println!` to use `Debug` formatting, we include `:?` in the print string, like -this: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; - - println!("a is {:?}", a); -} -``` - -If you run this, it should print the five values in the `a` array as desired: - -```bash -$ cargo run - Compiling arrays v0.1.0 (file:///projects/arrays) - Running `target/debug/arrays` -a is [1, 2, 3, 4, 5] -``` - -You’ll see this repeated later with other types. We’ll cover traits fully in -Chapter XX. - #### Accessing and Modifying Array Elements An array is a single chunk of memory, allocated on the stack. We can access diff --git a/src/ch05-00-structs.md b/src/ch05-00-structs.md index dcaffb211f..75691a7d70 100644 --- a/src/ch05-00-structs.md +++ b/src/ch05-00-structs.md @@ -210,6 +210,8 @@ Our function signature for `distance()` now says exactly what we mean: it calculates the distance between two `Point`s. And rather than `0` and `1`, we’ve got back our `x` and `y`. This is a win for clarity. +## Derived Traits + There’s one other thing that’s a bit strange here, this stuff above the `struct` declaration: @@ -220,8 +222,82 @@ struct Point { This is an annotation that tells the compiler our struct should get some default behavior for the `Debug`, `Copy`, and `Clone` traits. We talked about -`Debug` when we discussed arrays-- this lets us print out the `struct` and all -its fields when we use an instance of the struct with `println!`'s `{:?}`. We -talked about marking that types can be `Copy` and `Clone`-able in Chapter XX -when we discussed ownership. We'll continue exploring annotations and the -behaviors you can `derive` in Chapter XX. +marking that types can be `Copy` and `Clone`-able in Chapter XX when we +discussed ownership. `Debug` is the trait that enables us to print out our +struct so that we can see its value while we are debugging our code. + +So far, we’ve been printing values using `{}` in a `println!` macro. If we try +that with a struct, however, by default, we'll get an error. Say we have the +following program: + +```rust,ignore +struct Point { + x: f64, + y: f64, +} + +fn main() { + let p1 = Point { x: 0.0, y: 5.0}; + println!("Point 1: {}", p1); +} +``` + +This code tries to print the `p1` point directly, which may seem innocuous. But +running it produces the following output: + +```bash +$ cargo run + Compiling points v0.1.0 (file:///projects/points) +error: the trait bound `Point: std::fmt::Display` is not satisfied [--explain E0277] + --> src/main.rs:8:29 +8 |> println!("Point 1: {}", p1); + |> ^^ +:2:27: 2:58: note: in this expansion of format_args! +:3:1: 3:54: note: in this expansion of print! (defined in ) +src/main.rs:8:5: 8:33: note: in this expansion of println! (defined in ) +note: `Point` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string +note: required by `std::fmt::Display::fmt` +``` + +Whew! The core of the error is this part: *the trait bound `Point: +std::fmt::Display` is not satisfied*. `println!` can do many kinds of +formatting. By default, `{}` implements a kind of formatting known as +`Display`: output intended for direct end-user consumption. The primitive types +we’ve seen implement `Display`, as there’s only one way you’d show a `1` to a +user. But with structs, the output is less clear. Do you want commas or not? +What about the `{}`s? Should all the fields be shown? + +More complex types in the standard library and that are defined by the +programmer do not automatically implement `Display` formatting. Standard +library types implement `Debug` formatting, which is intended for the +programmer to see. The `#[derive(Debug)]` annotation lets us use a default +implementation of `Debug` formatting to easily get this ability for types we've +defined. To ask `println!` to use `Debug` formatting with our `Point`, we add +the annotation to derive the trait and include `:?` in the print string, like +this: + +```rust +#[derive(Debug)] +struct Point { + x: f64, + y: f64, +} + +fn main() { + let p1 = Point { x: 0.0, y: 5.0}; + println!("Point 1: {:?}", p1); +} +``` + +If you run this, it should print the values of each field in the `Point` struct +as desired: + +```bash +$ cargo run + Compiling points v0.1.0 (file:///projects/points) + Running `target/debug/points` +Point 1: Point { x: 0, y: 5 } +``` + +You’ll see this repeated later with other types. We’ll cover traits fully in +Chapter XX. From eb11d2b916e9eec6b984f0fada9e68706e08b017 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 14:56:29 -0400 Subject: [PATCH 138/204] Condense array discussion; mention Vec is preferred --- src/ch04-03-data-types.md | 51 ++++++--------------------------------- 1 file changed, 8 insertions(+), 43 deletions(-) diff --git a/src/ch04-03-data-types.md b/src/ch04-03-data-types.md index eff108eec5..eb8dc0d7a0 100644 --- a/src/ch04-03-data-types.md +++ b/src/ch04-03-data-types.md @@ -283,7 +283,8 @@ Another way to bind a name to a collection of multiple values is with an Arrays in Rust are different than arrays in some other languages because arrays in Rust have a fixed length-- once declared, they cannot grow or shrink in size. -In Rust, arrays look like this: +In Rust, the values going into an array are written as a comma separated list +inside square brackets: ```rust fn main() { @@ -291,23 +292,11 @@ fn main() { } ``` -The values going into an array are written as a comma separated list inside -square brackets. - -#### Type Annotation for Arrays - -When you specify an array’s type, you'd do so as such: - -```rust -fn main() { - let a: [i32; 5] = [1, 2, 3, 4, 5]; -} -``` - -Much like in a variable binding that uses type annotation, the array's type and -length come after the pattern name and a colon. This array has `5` values, -which are of the `i32` type. Unlike the values themselves, the type and array -length are separated by a semicolon. +While arrays can be useful since they are a primitive type, they aren't as +flexible as the `Vec` (short for "vector"), a similar collection type provided +by the standard library that _is_ allowed to grow or shrink in size. If you're +unsure whether to use an array or a `Vec`, you should probably go with a `Vec`, +and we'll discuss them in more detail in chapter XX. #### Accessing and Modifying Array Elements @@ -328,31 +317,7 @@ array, and `second` will bind to `2` at index `[1]` in the array. Note that these values are copied out of the array and into `first` and `second` when the `let` statement is called. That means if the array changes after the `let` statements, these bindings will not, and the two variables should retain their -values. For example, imagine you have the following code: - -```rust -fn main() { - let mut a = [1, 2, 3, 4, 5]; - - let first = a[0]; - - a[0] = 7; - - println!("The value of first is: {}", first); - println!("a is {:?}", a); -} -``` - -First, notice the use of `mut` in the array declaration. We had to declare -array `a` as `mut` to override Rust's default immutability. The line `a[0] = -7;` modifies the element at index 0 in the array, changing its value to `7`. -This happens after `first` is bound to the original value at index 0, so -`first` should still be equal to `1`. Running the code will show this is true: - -```text -The value of first is: 1 -a is [7, 2, 3, 4, 5] -``` +values. #### Invalid array element access From 7b37a5b4ac9029374a64edfe7daee67b1182d8cc Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 14:59:08 -0400 Subject: [PATCH 139/204] Remove bindings as arguments from functions Since we're assuming the reader has programmed in at least one language before, this will likely make sense to them. --- src/ch04-04-how-functions-work.md | 38 ------------------------------- 1 file changed, 38 deletions(-) diff --git a/src/ch04-04-how-functions-work.md b/src/ch04-04-how-functions-work.md index 413455b34b..7e87f7e9b9 100644 --- a/src/ch04-04-how-functions-work.md +++ b/src/ch04-04-how-functions-work.md @@ -147,44 +147,6 @@ The value of y is: 6 Since `5` is passed as the `x` argument and `6` is passed as the `y` argument, the two strings are printed with these values. -### Variable Bindings as Arguments - -It's also possible to create bindings and pass them in as arguments in Rust. -For example: - -```rust -fn main() { - let a = 5; - let b = 6; - - another_function(a, b); -} - -fn another_function(x: i32, y: i32) { - println!("The value of x is: {}", x); - println!("The value of y is: {}", y); -} -``` - -Instead of passing `5` and `6` directly, this first creates two bindings -containing the values and passes those bindings instead. When you run this, -you'll find that it has the same effect as just using integers: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of x is: 5 -The value of y is: 6 -``` - -Note that our bindings are called `a` and `b`, yet inside the function, we -refer to them by the names in the signature, `x` and `y`. Inside a function, -its parameters are in scope but the names of the bindings we passed as -parameters are not, so we need to use the parameter names within the function -block. Bindings passed as parameters don’t need to have the same names as the -arguments. - ### Function Bodies Function bodies are made up of a series of statements ending in an optional From 75b8ea124e950a7e1748e091efc6c63980f17372 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 15:47:36 -0400 Subject: [PATCH 140/204] Shorten type annotation explanation in data types --- src/ch04-03-data-types.md | 75 +++++++-------------------------------- 1 file changed, 12 insertions(+), 63 deletions(-) diff --git a/src/ch04-03-data-types.md b/src/ch04-03-data-types.md index eb8dc0d7a0..796a3320b4 100644 --- a/src/ch04-03-data-types.md +++ b/src/ch04-03-data-types.md @@ -1,73 +1,22 @@ ## Data Types Every value in Rust is of a certain *type*, which tells Rust what kind of data -is being given so it knows how to work with that data. You can usually rely on -Rust's ability to infer types to figure out the type of a binding, or you can -annotate it explicitly if needed. In this section, we'll look at a number of -types built into the language itself split into two subsets of Rust data types: -scalar and compound. First, let's look at how Rust deals with types. +is being given so it knows how to work with that data. In this section, we'll +look at a number of types built into the language itself split into two subsets +of Rust data types: scalar and compound. -### Type Inference and Annotation +Something to keep in mind throughout this section: Rust is a *statically typed* +language, which means that it must know the types of all bindings at compile +time. The compiler can usually infer what type we want to use based on the +value and how we use it. When many types are possible, such as when we +converted a `String` to a numeric type using `parse()` in the guessing game +tutorial, we can add a type annotation, like this: -Rust is a *statically typed* language, which means that it must know the types -of all bindings at compile time. However, you may have noticed that we didn’t -declare a type for `x` or `y` in our previous examples. - -This is because Rust can often tell the type of a binding without you having to -declare it. Annotating every single binding with a type can take uneccesary -time and make code noisy. To avoid this, Rust uses *type inference*, meaning -that it attempts to figure out the types of your bindings by looking at how the -binding is used. Let’s look at the the first `let` statement you wrote again: - -```rust -fn main() { - let x = 5; -} -``` - -When we bind `x` to `5`, the compiler determines that `x` should be a numeric -type based on the value it is bound to. Without any other information, it sets -the `x` variable's type to `i32` (a thirty-two bit integer type) by default. - -If we were to declare the type with the variable binding, that would be called -a *type annotation*. A `let` statement that includes a type annotation would -look like this: - -```text -let PATTERN: TYPE = VALUE; -``` - -The `let` statement now has a colon after the `PATTERN`, followed by the `TYPE` -name. Note that the colon and the `TYPE` go _after_ the `PATTERN`, not inside -the pattern itself. Given this structure, here's how you'd rewrite `let x = 5` -to use type annotation: - -```rust -fn main() { - let x: i32 = 5; -} -``` - -This does the same thing as `let x = 5` but explicitly states that `x` should -be of the `i32` type. This is a simple case, but more complex patterns with -multiple bindings can use type annotation, too. A binding with two variables -would look like this: - -```rust -fn main() { - let (x, y): (i32, i32) = (5, 6); -} +```rust,ignore +let x: i32 = 5; ``` -In the same way as we place the `VALUE` and the `PATTERN` in corresponding -positions, we also match up the position of the `TYPE` with the `PATTERN` it -corresponds to. - -There are times when multiple types could be correct, and there is not enough -information in the surrounding context for Rust to be able to tell which type -you want to use. In those cases type annotations are required. We will look at -some of those situations later, but for now, let's look at the types available -in Rust. +You will see some type annotations as we discuss the various data types. ### Scalar Types From ad88878ecf8172b8f622c2166299d6856f739208 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 16:08:26 -0400 Subject: [PATCH 141/204] Discuss multiple return values in ownership instead It's actually cooler to show a bit of motivation for it, imo. --- src/ch03-01-ownership.md | 12 +++++------ src/ch04-04-how-functions-work.md | 35 ------------------------------- 2 files changed, 6 insertions(+), 41 deletions(-) diff --git a/src/ch03-01-ownership.md b/src/ch03-01-ownership.md index d50a50d880..9f49a3efb9 100644 --- a/src/ch03-01-ownership.md +++ b/src/ch03-01-ownership.md @@ -451,7 +451,9 @@ owner goes out of scope, if it hasn’t been moved, it will `drop()`. This might seem a bit tedious, and it is. What if we want to let a function use a value but not take ownership? It’s quite annoying that anything we pass in -also needs to be passed back if we want to use it again. Like in this function: +also needs to be passed back if we want to use it again, in addition to any +data resulting from the body of the function that we might want to return as +well. It's _possible_ to return multiple values, using a tuple, like this: ```rust fn main() { @@ -469,8 +471,6 @@ fn calculate_length(s: String) -> (String, usize) { } ``` -This is too much ceremony: we have to use a tuple to give back the `String` as -well as the length. It’s a lot of work for a pattern that should be common. - -Luckily for us, Rust has a feature for this pattern, and it’s what the next -section is about. +But this is too much ceremony and a lot of work for a concept that should be +common. Luckily for us, Rust has a feature for this concept, and it’s what the +next section is about. diff --git a/src/ch04-04-how-functions-work.md b/src/ch04-04-how-functions-work.md index 7e87f7e9b9..99ab25b7b7 100644 --- a/src/ch04-04-how-functions-work.md +++ b/src/ch04-04-how-functions-work.md @@ -359,38 +359,3 @@ says that it will return an `i32`, but statements don’t evaluate to a value. Therefore, nothing is returned, which contradicts the function definition and results in an error. In this output, Rust gives an option to rectify this: it suggests removing the semicolon, which would fix the error. - -#### Returning Multiple Values - -By default, functions can only return single values. There’s a trick, however, -to get them to return multiple values: group them into a tuple! - -```rust -fn main() { - let (x, y) = two_numbers(); - - println!("The value of x is: {}", x); - println!("The value of y is: {}", y); -} - -fn two_numbers() -> (i32, i32) { - (5, 6) -} -``` - -Running this will give us the values: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of x is: 5 -The value of y is: 6 -``` - -Let's look at this more closely. First, we're assigning the return value of -calling `two_numbers()` to `x` and `y`. In the function signature, we would say -in plain English that the return type `(i32, i32)` translates to "a tuple with -two `i32`s in it". These two types are then applied to the tuple to be returned -by the function block. In this case, that tuple contains the values `5` and -`6`. This tuple is returned, and we destructure the tuple and assign the individual values to `x` and `y`. From b5ebd970460a38e9014e026d8f0a0ababc3b6646 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 16:13:51 -0400 Subject: [PATCH 142/204] Move doc comments into a future section about creating a library --- src/SUMMARY.md | 4 +++- src/ch03-06-comments.md | 40 -------------------------------- src/chYY-YY-documentation.md | 45 ++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 41 deletions(-) create mode 100644 src/chYY-YY-documentation.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 864c33f8a5..1edbc1468d 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -81,8 +81,10 @@ - [Using Rust from Other Languages]() - [`static`]() -- [Cargo]() +- [Creating a Library]() + - [Cargo]() - [Crates.io]() + - [Documentation](chYY-YY-documentation.md) - [Advanced Type System Features]() - [Associated Types]() diff --git a/src/ch03-06-comments.md b/src/ch03-06-comments.md index 7a96ae381b..88995480df 100644 --- a/src/ch03-06-comments.md +++ b/src/ch03-06-comments.md @@ -37,43 +37,3 @@ fn main() { ``` That’s all there is to it. Comments are not particularly complicated. - -## Documentation comments - -However, Rust has another kind of comment: a documentation comment. These -comments don’t affect the way that the code works, but they do work with Rust’s -tools. More specifically, the `rustdoc` tool that comes with Rust reads -documentation comments and produces HTML documentation from them. - -Documentation comments use an extra slash: - -```rust -/// The foo function doesn’t really do much. -fn foo() { -} - -/// We also can use -/// multiple comments here too, -/// like we did before -fn bar() { -} -``` - -This comment would then be interpreted by `rustdoc` as documenting the thing -that follows it: `foo()` and `bar()`. - -Because documentation comments have semantic meaning to `rustdoc`, the compiler -will pay attention to the placement of your documentation comments. For -example, a program with only this: - -```rust,ignore -/// What am I documenting? -``` - -Will give a compiler error: - -```text -src/main.rs:1:1: 1:27 error: expected item after doc comment -src/main.rs:1 /// What am I documenting? - ^~~~~~~~~~~~~~~~~~~~~~~~~~ -``` diff --git a/src/chYY-YY-documentation.md b/src/chYY-YY-documentation.md new file mode 100644 index 0000000000..1adb89e9de --- /dev/null +++ b/src/chYY-YY-documentation.md @@ -0,0 +1,45 @@ +## Documentation + + + +### Documentation comments + +Rust has another kind of comment: a documentation comment. These +comments don’t affect the way that the code works, but they do work with Rust’s +tools. More specifically, the `rustdoc` tool that comes with Rust reads +documentation comments and produces HTML documentation from them. + +Documentation comments use an extra slash: + +```rust +/// The foo function doesn’t really do much. +fn foo() { +} + +/// We also can use +/// multiple comments here too, +/// like we did before +fn bar() { +} +``` + +This comment would then be interpreted by `rustdoc` as documenting the thing +that follows it: `foo()` and `bar()`. + +Because documentation comments have semantic meaning to `rustdoc`, the compiler +will pay attention to the placement of your documentation comments. For +example, a program with only this: + +```rust,ignore +/// What am I documenting? +``` + +Will give a compiler error: + +```text +src/main.rs:1:1: 1:27 error: expected item after doc comment +src/main.rs:1 /// What am I documenting? + ^~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +### Generating HTML documentation From 287d9b175b196e8de0c605359e3f2afde1a5a3c5 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 16:20:14 -0400 Subject: [PATCH 143/204] Remove doc comments to go in a future section about library docs --- src/ch04-05-comments.md | 54 ----------------------------------------- 1 file changed, 54 deletions(-) diff --git a/src/ch04-05-comments.md b/src/ch04-05-comments.md index cb8eaf3fb6..a4c950b9ea 100644 --- a/src/ch04-05-comments.md +++ b/src/ch04-05-comments.md @@ -39,57 +39,3 @@ fn main() { ``` That’s all there is to it. Comments are not particularly complicated. - -### Documentation Comments - -Rust has another kind of comment: a *documentation comment*. These comments -don’t affect the way that the code works, but they do work with Rust’s tools. -More specifically, the `rustdoc` tool can read documentation comments and -produce HTML documentation from them. This documentation's intended audience is -usually people who are using your code, so that they know how to interact with -it. Regular comments won't be shown in `rustdoc` generated HTML, so their -intended audience is people who are reading and editing your code. - -Documentation comments use an extra slash, like this: - -```rust -/// The foo function doesn’t really do much. -fn foo() { - -} - -/// Documentation comments can use -/// multiple line comments too, -/// like we did before. -fn bar() { - -} -``` - -The `rustdoc` tool will interpret each comment in this example as documenting -the thing that follows it. The first comment would be used to document the -`foo()` function and the second comment would document the `bar()` function. - -Because documentation comments have semantic meaning to `rustdoc`, the compiler -will pay attention to the placement of your documentation comments. For -example, a program containing only this: - -```rust,ignore -/// What am I documenting? -``` - -Will give the following compiler error: - -```bash -src/main.rs:1:1: 1:27 error: expected item after doc comment -src/main.rs:1 /// What am I documenting? - ^~~~~~~~~~~~~~~~~~~~~~~~~~ -``` - -This happens because Rust expects a document comment to be associated with -whatever code comes directly after it, so it sees that a document comment alone -must be a mistake. - -Providing documentation for libraries is a best practice that the Rust community -strives to do to be helpful to each other. We'll cover how you can generate -great API documentation for your library in more detail in Chapter XX. From 8104951921e7625352c7c72570035ab171ba3215 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 16:58:39 -0400 Subject: [PATCH 144/204] Talk about `for` more than `loop` and `while` Since that's the most common loop in Rust and has some benefits, let's encourage it. --- src/ch04-06-control-flow.md | 112 ++++++++++++++---------------------- 1 file changed, 42 insertions(+), 70 deletions(-) diff --git a/src/ch04-06-control-flow.md b/src/ch04-06-control-flow.md index 3e9941d80c..4fd812db1d 100644 --- a/src/ch04-06-control-flow.md +++ b/src/ch04-06-control-flow.md @@ -307,79 +307,27 @@ again! ^Cagain! ``` -That `^C` there is where I hit `control-c`. You may or may not see "again!" printed after the `^C`, depending on where the code was in the loop when it received the signal to halt. +That `^C` there is where I hit `control-c`. You may or may not see "again!" +printed after the `^C`, depending on where the code was in the loop when it +received the signal to halt. Fortunately, Rust provides another, more reliable way to break out of a loop. We can place the `break` keyword within the loop to tell the program when to -stop executing the loop. Try this version of the program out: - -```rust -fn main() { - loop { - println!("once!"); - break; - } -} -``` - -If you run this program, you’ll see that it only executes one time: - -```bash -$ cargo run - Compiling loops v0.1.0 (file:///projects/loops) - Running `target/debug/loops` -once! -``` - -When a Rust program hits a `break` statement, it will exit the current loop. -This on its own is not very useful; if we wanted to print somtheing just once, -we wouldn't put it in a loop. This is where conditions come in again. +stop executing the loop. Recall that we did this in the guessing game to exit +the program when the user won the game by guessing the number correctly. #### Conditional Loops With `while` -To make `break` useful, we need to give our program a condition. While the -condition is true, the loop runs. When the condition ceases to be true, the -`break` code runs, stopping the loop. - -Try this example: - -```rust -fn main() { - let mut number = 3; - - loop { - if number != 0 { - println!("{}!", number); - - number = number - 1; - } else { - break; - } - } - - println!("LIFTOFF!!!"); -} -``` - -If we run this, we’ll get: - -```bash - Compiling loops v0.1.0 (file:///projects/loops) - Running `target/debug/loops` -3! -2! -1! -LIFTOFF!!! -``` - -This program loops three times, counting down each time. Finally, after the -loop, it prints another message, then exits. +A useful thing that many programs do is have a condition that can be evaluated +within a loop. While the condition is true, the loop runs. When the condition +ceases to be true, we call `break`, stopping the loop. This could be +implemented with a combination of `loop`, `if`, `else`, and `break`; try to do +that now if you'd like! -The core of this example is in the combination of `loop`, `if`, `else`, and -`break`. We want to `loop`, but only while some sort of condition is true. As -soon as it isn't, we want to `break` out of the loop. This pattern is so common -that Rust has a more efficient language construct for it, called a `while` -loop. Here's the same example, but using `while` instead: +But this pattern is so common that Rust has a more efficient language construct +for it, called a `while` loop. Here's an example using `while`: this program +loops three times, counting down each time. Finally, after the loop, it prints +another message, then exits: ```rust fn main() { @@ -395,12 +343,13 @@ fn main() { } ``` -This gets rid of a lot of nesting, and it's more clear. While a condition -holds, run this code; otherwise, do nothing. +This gets rid of a lot of nesting that would be necessary if we used `loop`, +`if`, `else`, and `break`, and it's more clear. While a condition holds, run +this code; otherwise, exit the loop. #### Looping Though a Collection with `for` -We can use this `while` construct to loop over the elements of a collection, +We could use this `while` construct to loop over the elements of a collection, like an array. For example: ```rust @@ -466,4 +415,27 @@ array. If you're wondering about the `.iter()` code in this example, keep reading! We will cover method syntax generally in Chapter XX and iterators specifically in -Chapter XX. For now, though, let's get into the concept of ownership. +Chapter XX. + +The safety and conciseness of `for` loops make them the most commonly used loop +construct in Rust. Even in situations where you want to run some code a certain +number of times, like our countdown example that used a `while` loop, most +Rustaceans would use a `for` loop. The way to do that is using a `Range`, which +is a type provided by the standard library that generates numbers starting from +one number and ending before another number. Here's what the countdown would +look like with a for loop, and using another method we haven't yet talked +about, `.rev()`, to reverse the range: + +```rust +fn main() { + for number in (1..4).rev() { + println!("{}!", number); + } + println!("LIFTOFF!!!"); +} +``` + +That's a bit nicer, isn't it? + +Now that you know how Rust does things that most other languages can do, let's +talk about a concept that _doesn't_ commonly exist: ownership. From 287b1472680410406c2e39a3080e0b93ce2833db Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 17:03:40 -0400 Subject: [PATCH 145/204] Sorry steve, bobby frost is going --- src/ch04-06-control-flow.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/ch04-06-control-flow.md b/src/ch04-06-control-flow.md index 4fd812db1d..118b1b3de4 100644 --- a/src/ch04-06-control-flow.md +++ b/src/ch04-06-control-flow.md @@ -8,14 +8,6 @@ loops. ### `if` Expressions -> Two roads diverged in a yellow wood, -> And sorry I could not travel both -> And be one traveler, long I stood -> And looked down one as far as I could -> To where it bent in the undergrowth; -> -> - Robert Frost, “The Road Not Taken” - An `if` expression allows us to branch our code depending on conditions. We provide a condition and then say, "If this condition is met, then run this block of code. If the condition is not met, do not run this block of code." From eb6d860033d0059ca29364aecb39e391cf629174 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 17:16:39 -0400 Subject: [PATCH 146/204] Condense the `if` explanation It's a little bit *too* detailed, for people coming from other languages. --- src/ch04-06-control-flow.md | 85 +++++++++++++------------------------ 1 file changed, 30 insertions(+), 55 deletions(-) diff --git a/src/ch04-06-control-flow.md b/src/ch04-06-control-flow.md index 118b1b3de4..c646e5207b 100644 --- a/src/ch04-06-control-flow.md +++ b/src/ch04-06-control-flow.md @@ -25,18 +25,23 @@ Write this sample program using `if` and save it in the *branches* directory in ```rust fn main() { - let condition = true; + let number = 3; - if condition { + if number < 5 { println!("condition was true"); + } else { + println!("condition was false"); } } ``` -The `condition` variable is a boolean; here, it's set to true. All `if` -expressions start with `if`, which is followed by a condition. The block of code -we want to execute if the condition is true goes immediately after the -condition, inside curly braces. These blocks are sometimes called ‘arms’. +All `if` expressions start with `if`, which is followed by a condition. In this +case, our condition is checking if our variable binding `number` has a value +that is less than 5. The block of code we want to execute if the condition is +true goes immediately after the condition, inside curly braces. These blocks +are sometimes called ‘arms’. We can optionally also include an `else` +statement, which we have chosen to do here. `else` gives the program a block of +code to execute should `condition` evaluate to false. Try running this code, and you should see output like this: @@ -47,41 +52,15 @@ $ cargo run condition was true ``` -Let’s try changing the value of `condition` to `false` as follows to see what -happens: +Let’s try changing the value of `number` to a value that makes the condition +`false` to see what happens: -```rust - let condition = false; +```rust,ignore +let number = 7; ``` Run the program again, and look at the output: -```bash -$ cargo run - Compiling branches v0.1.0 (file:///projects/branches) - Running `target/debug/branches` -``` - -Nothing was output, because the condition was false and the `if` block was not -run. - -We can optionally also include an `else` statement, which gives the program a -block of code to execute should `condition` evaluate to false. - -```rust -fn main() { - let condition = false; - - if condition { - println!("condition was true"); - } else { - println!("condition was false"); - } -} -``` - -If we run this program, the output will look like: - ```bash $ cargo run Compiling branches v0.1.0 (file:///projects/branches) @@ -89,35 +68,31 @@ $ cargo run condition was false ``` -This time, because `condition` was false and we have an `else` block, the -`else` block was executed. - It’s also worth noting that `condition` here _must_ be a `bool`. To see what happens if the condition isn't a `bool`, try running this code: ```rust,ignore fn main() { - let condition = 5; + let number = 3; - if condition { - println!("condition was five"); + if number { + println!("number was three"); } } ``` -The `condition` variable is assigned a value of `5` this time, and Rust will +The `if` condition evaluates to a value of `3` this time, and Rust will complain about it: ```bash Compiling branches v0.1.0 (file:///projects/branches) -src/main.rs:4:8: 4:17 error: mismatched types: - expected `bool`, - found `_` -(expected bool, - found integral variable) [E0308] -src/main.rs:4 if condition { - ^~~~~~~~~ -src/main.rs:4:8: 4:17 help: run `rustc --explain E0308` to see a detailed explanation +error: mismatched types [--explain E0308] + --> src/main.rs:4:8 +4 |> if number { + |> ^^^^^^ expected bool, found integral variable +note: expected type `bool` +note: found type `_` + error: aborting due to previous error Could not compile `branches`. ``` @@ -129,15 +104,15 @@ languages like Ruby or JavaScript. We must be explicit and always give `if` a ```rust fn main() { - let condition = 5; + let number = 3; - if condition != 0 { - println!("condition was something other than zero"); + if number != 0 { + println!("number was something other than zero"); } } ``` -Running this will print "condition was something other than zero". +Running this will print "number was something other than zero". #### Multiple Conditions with `else if` From 37101e52246667bed17dc7095e88353b6acd7a7b Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 17:22:41 -0400 Subject: [PATCH 147/204] Swap the order of common programming concepts & ownership again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 😂😂😂 --- src/SUMMARY.md | 22 +++++++++---------- ...00-common-programming-concepts-in-rust.md} | 10 ++++----- src/ch03-00-understanding-ownership.md | 5 ----- ...03-01-variable-bindings-and-mutability.md} | 0 ...03-data-types.md => ch03-02-data-types.md} | 0 ...-work.md => ch03-03-how-functions-work.md} | 0 ...h04-05-comments.md => ch03-04-comments.md} | 0 ...ontrol-flow.md => ch03-05-control-flow.md} | 0 src/ch04-00-understanding-ownership.md | 6 +++++ ...3-01-ownership.md => ch04-01-ownership.md} | 0 ...md => ch04-02-references-and-borrowing.md} | 0 src/{ch03-03-slices.md => ch04-03-slices.md} | 0 12 files changed, 22 insertions(+), 21 deletions(-) rename src/{ch04-00-common-programming-concepts-in-rust.md => ch03-00-common-programming-concepts-in-rust.md} (68%) delete mode 100644 src/ch03-00-understanding-ownership.md rename src/{ch04-01-variable-bindings-and-mutability.md => ch03-01-variable-bindings-and-mutability.md} (100%) rename src/{ch04-03-data-types.md => ch03-02-data-types.md} (100%) rename src/{ch04-04-how-functions-work.md => ch03-03-how-functions-work.md} (100%) rename src/{ch04-05-comments.md => ch03-04-comments.md} (100%) rename src/{ch04-06-control-flow.md => ch03-05-control-flow.md} (100%) create mode 100644 src/ch04-00-understanding-ownership.md rename src/{ch03-01-ownership.md => ch04-01-ownership.md} (100%) rename src/{ch03-02-references-and-borrowing.md => ch04-02-references-and-borrowing.md} (100%) rename src/{ch03-03-slices.md => ch04-03-slices.md} (100%) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 85a67ae34f..0146327e59 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -6,17 +6,17 @@ - [Guessing Game Tutorial](ch02-00-guessing-game-tutorial.md) -- [Understanding Ownership](ch03-00-understanding-ownership.md) - - [Ownership](ch03-01-ownership.md) - - [References & Borrowing](ch03-02-references-and-borrowing.md) - - [Slices](ch03-03-slices.md) - -- [Common Programming Concepts in Rust](ch04-00-common-programming-concepts-in-rust.md) - - [Variable Bindings and Mutability](ch04-01-variable-bindings-and-mutability.md) - - [Data Types](ch04-03-data-types.md) - - [How Functions Work](ch04-04-how-functions-work.md) - - [Comments](ch04-05-comments.md) - - [Control Flow](ch04-06-control-flow.md) +- [Common Programming Concepts in Rust](ch03-00-common-programming-concepts-in-rust.md) + - [Variable Bindings and Mutability](ch03-01-variable-bindings-and-mutability.md) + - [Data Types](ch03-02-data-types.md) + - [How Functions Work](ch03-03-how-functions-work.md) + - [Comments](ch03-04-comments.md) + - [Control Flow](ch03-05-control-flow.md) + +- [Understanding Ownership](ch04-00-understanding-ownership.md) + - [Ownership](ch04-01-ownership.md) + - [References & Borrowing](ch04-02-references-and-borrowing.md) + - [Slices](ch04-03-slices.md) - [Structs](ch05-00-structs.md) - [Method Syntax](ch05-01-method-syntax.md) diff --git a/src/ch04-00-common-programming-concepts-in-rust.md b/src/ch03-00-common-programming-concepts-in-rust.md similarity index 68% rename from src/ch04-00-common-programming-concepts-in-rust.md rename to src/ch03-00-common-programming-concepts-in-rust.md index 99ed50701f..8fa09a6b13 100644 --- a/src/ch04-00-common-programming-concepts-in-rust.md +++ b/src/ch03-00-common-programming-concepts-in-rust.md @@ -1,10 +1,10 @@ # Common Programming Concepts in Rust -Now that we've seen some of the features that make Rust unique, let's look at -concepts that appear in almost every programming language and see how they work -in Rust. Many programming languages have much in common at their core. None of -the concepts presented in this chapter are unique to Rust, but we’ll discuss -Rust’s particular syntax and conventions concerning these common concepts. +Let's look at concepts that appear in almost every programming language and see +how they work in Rust. Many programming languages have much in common at their +core. None of the concepts presented in this chapter are unique to Rust, but +we’ll discuss Rust’s particular syntax and conventions concerning these common +concepts. Specifically, we’ll be talking about variable bindings, basic types, functions, comments, and control flow. These foundations will be in every Rust diff --git a/src/ch03-00-understanding-ownership.md b/src/ch03-00-understanding-ownership.md deleted file mode 100644 index ba39afe4ed..0000000000 --- a/src/ch03-00-understanding-ownership.md +++ /dev/null @@ -1,5 +0,0 @@ -# Understanding Ownership - -Now let's look at Rust’s most unique feature: ownership. We’ll also talk about -several related features: borrowing, slices, and lifetimes, as well as how Rust -lays things out in memory. diff --git a/src/ch04-01-variable-bindings-and-mutability.md b/src/ch03-01-variable-bindings-and-mutability.md similarity index 100% rename from src/ch04-01-variable-bindings-and-mutability.md rename to src/ch03-01-variable-bindings-and-mutability.md diff --git a/src/ch04-03-data-types.md b/src/ch03-02-data-types.md similarity index 100% rename from src/ch04-03-data-types.md rename to src/ch03-02-data-types.md diff --git a/src/ch04-04-how-functions-work.md b/src/ch03-03-how-functions-work.md similarity index 100% rename from src/ch04-04-how-functions-work.md rename to src/ch03-03-how-functions-work.md diff --git a/src/ch04-05-comments.md b/src/ch03-04-comments.md similarity index 100% rename from src/ch04-05-comments.md rename to src/ch03-04-comments.md diff --git a/src/ch04-06-control-flow.md b/src/ch03-05-control-flow.md similarity index 100% rename from src/ch04-06-control-flow.md rename to src/ch03-05-control-flow.md diff --git a/src/ch04-00-understanding-ownership.md b/src/ch04-00-understanding-ownership.md new file mode 100644 index 0000000000..9989d95439 --- /dev/null +++ b/src/ch04-00-understanding-ownership.md @@ -0,0 +1,6 @@ +# Understanding Ownership + +Ownership is important to understand: it's Rust's most unique feature, and +enables Rust to make memory safety guarantees without needing a garbage +collector. We’ll also talk about several related features: borrowing, slices, +and lifetimes, as well as how Rust lays things out in memory. diff --git a/src/ch03-01-ownership.md b/src/ch04-01-ownership.md similarity index 100% rename from src/ch03-01-ownership.md rename to src/ch04-01-ownership.md diff --git a/src/ch03-02-references-and-borrowing.md b/src/ch04-02-references-and-borrowing.md similarity index 100% rename from src/ch03-02-references-and-borrowing.md rename to src/ch04-02-references-and-borrowing.md diff --git a/src/ch03-03-slices.md b/src/ch04-03-slices.md similarity index 100% rename from src/ch03-03-slices.md rename to src/ch04-03-slices.md From deb9e466bc29a427a9cf80f624c7051821ca1fbf Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 30 Jul 2016 17:38:35 -0400 Subject: [PATCH 148/204] Ignore partial code blocks, unindent them --- src/ch04-03-slices.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index 889d423bc3..99fb487fe9 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -36,16 +36,16 @@ fn first_word(s: &String) -> usize { Let’s break that down a bit: -```rust - let bytes = s.as_bytes(); +```rust,ignore +let bytes = s.as_bytes(); ``` Since we need to go through the String element by element and check if a value is a space, we will convert our String to an array of bytes using the `.as_bytes()` method. -```rust - for (i, &byte) in bytes.iter().enumerate() { +```rust,ignore +for (i, &byte) in bytes.iter().enumerate() { ``` We will be discussing iterators in more detail in Chapter XX, but for @@ -59,12 +59,12 @@ Since it’s a tuple, we can use patterns, just like elsewhere in Rust. So we match against the tuple with i for the index and &byte for the byte itself. -```rust - if byte == 32 { - return i; - } +```rust,ignore + if byte == 32 { + return i; } - s.len() +} +s.len() ``` We search for the value 32, which represents a space in UTF-8. If we find one, we return the From 174d50ad9bd18017678a978b4cf0364f67dbbbac Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 30 Jul 2016 19:35:46 +0200 Subject: [PATCH 149/204] Few improvements --- src/chXX-patterns.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/chXX-patterns.md b/src/chXX-patterns.md index 93c07349f0..c912f5b792 100644 --- a/src/chXX-patterns.md +++ b/src/chXX-patterns.md @@ -2,8 +2,7 @@ We've actually used patterns a few times so far: they're used in `let` bindings, in function arguments, and in the `match` expression. Patterns have a -lot more abilities than we have demonstrated so far, so in this section, we'll -cover all of the different things they can do. Any of these abilities work in +lot more abilities than we have demonstrated so far, so we'll cover some of the most commonly used ones in this section. Any of these abilities work in any place where a pattern is used. ## `let` statements From da3283539c47831be8abd7357f1d210c90f06901 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 1 Aug 2016 21:47:48 -0400 Subject: [PATCH 150/204] Rework the intro to cargo Instead of converting hello world to cargo and THEN creating a new cargo project, just create a new cargo project and look at the differences. This makes this section a bit less repetitive and doing the usual thing first. --- src/ch01-02-hello-world.md | 320 +++++++++++++++++-------------------- 1 file changed, 150 insertions(+), 170 deletions(-) diff --git a/src/ch01-02-hello-world.md b/src/ch01-02-hello-world.md index bac171affc..d397ae6104 100644 --- a/src/ch01-02-hello-world.md +++ b/src/ch01-02-hello-world.md @@ -29,8 +29,8 @@ $ cd hello_world ## Writing and Running a Rust Program -Next, make a new source file and call it *main.rs*. Rust files always end -in a *.rs* extension. If you’re using more than one word in your filename, use +Next, make a new source file and call it *main.rs*. Rust files always end with +the *.rs* extension. If you’re using more than one word in your filename, use an underscore to separate them. For example, you'd use *hello_world.rs* rather than *helloworld.rs*. @@ -51,7 +51,7 @@ $ ./main Hello, world! ``` -In Windows, just replace `main` with `main.exe`. Regardless of your operating +On Windows, just replace `main` with `main.exe`. Regardless of your operating system, you should see the string `Hello, world!` print to the terminal. If you did, then congratulations! You've officially written a Rust program. That makes you a Rust programmer! Welcome. @@ -71,8 +71,9 @@ These lines define a *function* in Rust. The `main` function is special: it's the first thing that is run for every executable Rust program. The first line says, “I’m declaring a function named `main` that takes no arguments and returns nothing.” If there were arguments, they would go inside the parentheses -(`(` and `)`), because we aren’t returning anything from this function, we -have omitted the return type entirely. +(`(` and `)`). We aren’t returning anything from this function, so we have +omitted the return type entirely. If there was a return type, there would be a +`->` and the return type after the parentheses. Also note that the function body is wrapped in curly braces (`{` and `}`). Rust requires these around all function bodies. It's considered good style to put @@ -89,15 +90,15 @@ This line does all of the work in this little program: it prints text to the screen. There are a number of details that are important here. The first is that it’s indented with four spaces, not tabs. -The second important part is the `println!()` line. This is calling a Rust -*macro*, which is how metaprogramming is done in Rust. If it were calling a -function instead, it would look like this: `println()` (without the !). We'll -discuss Rust macros in more detail in Chapter XX, but for now you just need to -know that when you see a `!` that means that you’re calling a macro instead of -a normal function. +The second important part is `println!()`. This is calling a Rust *macro*, +which is how metaprogramming is done in Rust. If it were calling a function +instead, it would look like this: `println()` (without the `!`). We'll discuss +Rust macros in more detail in Chapter XX, but for now you just need to know +that when you see a `!` that means that you’re calling a macro instead of a +normal function. Next is `"Hello, world!"` which is a *string*. We pass this string as an -argument to `println!`, which prints the string to the screen. Easy enough! +argument to `println!()`, which prints the string to the screen. Easy enough! The line ends with a semicolon (`;`). The `;` indicates that this expression is over, and the next one is ready to begin. Most lines of Rust code end with a @@ -133,7 +134,7 @@ $ dir main.exe main.rs ``` -This shows we have two files: the source code, with an `.rs` extension, and the +This shows we have two files: the source code, with the `.rs` extension, and the executable (`main.exe` on Windows, `main` everywhere else). All that's left to do from here is run the `main` or `main.exe` file, like this: @@ -162,232 +163,211 @@ programs. # Hello, Cargo! Cargo is Rust’s build system and package manager, and Rustaceans use Cargo to -manage their Rust projects. Cargo manages three things: building your code, -downloading the libraries your code depends on, and building those libraries. -We call libraries your code needs ‘dependencies’ since your code depends on -them. +manage their Rust projects because it makes a lot of tasks easier. For example, +Cargo takes care of building your code, downloading the libraries your code +depends on, and building those libraries. We call libraries your code needs +‘dependencies’ since your code depends on them. -The simplest Rust programs don’t have any dependencies, so right now, you'd -only use the first part of its functionality. As you write more complex Rust -programs, you’ll want to add dependencies, and if you start off using Cargo, -that will be a lot easier to do. +The simplest Rust programs, like the one we've written so far, don’t have any +dependencies, so right now, you'd only be using the part of Cargo that can take +care of building your code. As you write more complex Rust programs, you’ll +want to add dependencies, and if you start off using Cargo, that will be a lot +easier to do. As the vast, vast majority of Rust projects use Cargo, we will assume that you’re using it for the rest of the book. Cargo comes installed with Rust -itself, if you used the official installers. If you installed Rust through some -other means, you can check if you have Cargo installed by typing: +itself, if you used the official installers as covered in the Installation +chapter. If you installed Rust through some other means, you can check if you +have Cargo installed by typing the following into your terminal: ```bash $ cargo --version ``` -Into a terminal. If you see a version number, great! If you see an error like -‘`command not found`’, then you should look at the documentation for the system -in which you installed Rust, to determine if Cargo is separate. +If you see a version number, great! If you see an error like `command not +found`, then you should look at the documentation for the way you installed +Rust to determine how to install Cargo separately. -## Converting to Cargo +## Creating a Project with Cargo -Let’s convert the Hello World program to Cargo. To Cargo-fy a project, you need -to do three things: - -1. Put your source file in the right directory. -2. Get rid of the old executable (`main.exe` on Windows, `main` everywhere - else). -3. Make a Cargo configuration file. - -Let's get started! - -### Creating a Source Directory and Removing the Old Executable - -First, go back to your terminal, move to your *hello_world* directory, and -enter the following commands: +Let's create a new project using Cargo and look at how it differs from our +project in `hello_world`. Go back to your projects directory (or wherever you +decided to put your code): ```bash -$ mkdir src -$ mv main.rs src/main.rs # or 'move main.rs src/main.rs' on Windows -$ rm main # or 'del main.exe' on Windows +$ cd ~/projects ``` -Cargo expects your source files to live inside a *src* directory, so do that -first. This leaves the top-level project directory (in this case, -*hello_world*) for READMEs, license information, and anything else not related -to your code. In this way, using Cargo helps you keep your projects nice and -tidy. There's a place for everything, and everything is in its place. - -Now, move *main.rs* into the *src* directory, and delete the compiled file you -created with `rustc`. As usual, replace `main` with `main.exe` if you're on -Windows. - -This example retains `main.rs` as the source filename because it's creating an -executable. If you wanted to make a library instead, you'd name the file -`lib.rs`. This convention is used by Cargo to successfully compile your -projects, but it can be overridden if you wish. - -### Creating a Configuration File - -Next, create a new file inside your *hello_world* directory, and call it -`Cargo.toml`. +And then run: -Make sure to capitalize the `C` in `Cargo.toml`, or Cargo won't know what to do -with the configuration file. +```bash +$ cargo new hello_cargo --bin +$ cd hello_cargo +``` -This file is in the *[TOML]* (Tom's Obvious, Minimal Language) format. TOML is -similar to INI, but has some extra goodies, and is used as Cargo’s -configuration format. +We passed the `--bin` argument to `cargo new` because our goal is to make an +executable application, as opposed to a library. Executables are often called +*binaries* (as in `/usr/bin`, if you’re on a Unix system). `hello_cargo` is the +name we've chosen for our project, and Cargo creates its files in a directory +of the same name that we can then go into. -[TOML]: https://github.com/toml-lang/toml +If we list the files in the `hello_cargo` directory, we can see that Cargo has +generated two files and one directory for us: a `Cargo.toml` and a *src* +directory with a *main.rs* file inside. It has also initialized a new `git` +repository in the `hello_cargo` directory for us; you can change this to use a +different version control system, or no version control system, by using the +`--vcs` flag. -Inside this file, type the following information: +Open up `Cargo.toml` in your text editor of choice. It should look something +like this: ```toml [package] -name = "hello_world" +name = "hello_cargo" version = "0.1.0" -authors = ["Your name "] +authors = ["Your Name "] [dependencies] ``` -The first line, `[package]`, indicates that the following statements are -configuring a package. As we add more information to this file, we’ll add other -sections, but for now, we just have the package configuration. +This file is in the *[TOML]* (Tom's Obvious, Minimal Language) format. TOML is +similar to INI but has some extra goodies and is used as Cargo’s +configuration format. + +[TOML]: https://github.com/toml-lang/toml + +The first line, `[package]`, is a section heading that indicates that the +following statements are configuring a package. As we add more information to +this file, we’ll add other sections. The next three lines set the three bits of configuration that Cargo needs to -know to compile your program: its name, what version it is, and who wrote it. -Cargo gets this information from your environment. If it’s not correct, go ahead -and fix that and save the file. +see in order to know that it should compile your program: its name, what +version it is, and who wrote it. Cargo gets your name and email information +from your environment. If it’s not correct, go ahead and fix that and save the +file. The last line, `[dependencies]`, is the start of a section for you to list any -crates that your project will depend on, so that Cargo knows to download and +crates that your project will depend on so that Cargo knows to download and compile those too. We won't need any other crates for this project, but we will in the guessing game tutorial in the next chapter. -## Building and Running a Cargo Project - -With your *Cargo.toml* file in place in your project's root directory, you -should be ready to build and run your Hello World program! To do so, enter the -following commands: +Now let's look at `src/main.rs`: -```bash -$ cargo build - Compiling hello_world v0.1.0 (file:///home/yourname/projects/hello_world) -$ ./target/debug/hello_world -Hello, world! +```rust +fn main() { + println!("Hello, world!"); +} ``` -Bam! If all goes well, `Hello, world!` should print to the terminal once more. +Cargo has generated a "Hello World!" for you, just like the one we wrote +earlier! So that part is the same. The differences between our previous project +and the project generated by Cargo that we've seen so far are: -You just built a project with `cargo build` and ran it with -`./target/debug/hello_world`, but you can actually do both in one step with -`cargo run` as follows: +1. Our code goes in the `src` directory +2. The top level contains a `Cargo.toml` configuration file + +Cargo expects your source files to live inside the *src* directory so that the +top-level project directory is just for READMEs, license information, +configuration files, and anything else not related to your code. In this way, +using Cargo helps you keep your projects nice and tidy. There's a place for +everything, and everything is in its place. + +If you started a project that doesn't use Cargo, as we did with our project in +the `hello_world` directory, you can convert it to a project that does use +Cargo by moving your code into the `src` directory and creating an appropriate +`Cargo.toml`. + +## Building and Running a Cargo Project + +Now let's look at what's different about building and running your Hello World +program through Cargo! To do so, enter the following commands: ```bash -$ cargo run - Running `target/debug/hello_world` -Hello, world! +$ cargo build + Compiling hello_cargo v0.1.0 (file:///home/yourname/projects/hello_cargo) ``` -Notice that this example didn’t re-build the project. Cargo figured out that -the file hasn’t changed, and so it just ran the binary. If you'd modified your -source code, Cargo would have rebuilt the project before running it, and you -would have seen something like this: +This should have created an executable file in `target/debug/hello_cargo` (or `target/debug/hello_cargo.exe` on Windows), which you can run with this command: ```bash -$ cargo run - Compiling hello_world v0.1.0 (file:///home/yourname/projects/hello_world) - Running `target/debug/hello_world` +$ ./target/debug/hello_cargo # or ./target/debug/hello_cargo.exe on Windows Hello, world! ``` -Cargo checks to see if any of your project’s files have been modified, and only -rebuilds your project if they’ve changed since the last time you built it. - -With simple projects, Cargo doesn't bring a whole lot over just using `rustc`, -but it will become useful in the future. With complex projects composed of multiple -crates, it’s much easier to let Cargo coordinate the build. With Cargo, you can -just run `cargo build`, and it should work the right way. - -## Building for Release - -When your project is finally ready for release, you can use `cargo build ---release` to compile your project with optimizations. These optimizations make -your Rust code run faster, but turning them on makes your program take longer -to compile. This is why there are two different profiles, one for development, -and one for building the final program you’ll give to a user. +Bam! If all goes well, `Hello, world!` should print to the terminal once more. -Running this command also causes Cargo to create a new file called -*Cargo.lock*, which looks like this: +Running `cargo build` for the first time also causes Cargo to create a new file +at the top level called *Cargo.lock*, which looks like this: ```toml [root] -name = "hello_world" +name = "hello_cargo" version = "0.1.0" ``` Cargo uses the *Cargo.lock* file to keep track of dependencies in your -application. This is the Hello World project's *Cargo.lock* file. This project -doesn't have dependencies, so the file is a bit sparse. Realistically, you -won't ever need to touch this file yourself; just let Cargo handle it. - -That’s it! If you've been following along, you should have successfully built -`hello_world` with Cargo. +application. This project doesn't have dependencies, so the file is a bit +sparse. Realistically, you won't ever need to touch this file yourself; just +let Cargo handle it. -Even though the project is simple, it now uses much of the real tooling you’ll -use for the rest of your Rust career. In fact, you can expect to start -virtually all Rust projects with some variation on the following commands: +We just built a project with `cargo build` and ran it with +`./target/debug/hello_cargo`, but we can actually do both in one step with +`cargo run` as follows: ```bash -$ git clone someurl.com/foo -$ cd foo -$ cargo build +$ cargo run + Running `target/debug/hello_cargo` +Hello, world! ``` -## Making A New Cargo Project the Easy Way - -You don’t have to go through that previous process every time you want to start -a new project! Cargo can quickly make a bare-bones project directory that you -can start developing in right away. - -To start a new project with Cargo, enter `cargo new` at the command line: +Notice that this time, we didn't see the output that Cargo was compiling +`hello_cargo`. Cargo figured out that the files haven’t changed, so it just ran +the binary. If you had modified your source code, Cargo would have rebuilt the +project before running it, and you would have seen something like this: ```bash -$ cargo new hello_world --bin +$ cargo run + Compiling hello_cargo v0.1.0 (file:///home/yourname/projects/hello_cargo) + Running `target/debug/hello_cargo` +Hello, world! ``` -This command passes `--bin` because the goal is to get straight to making an -executable application, as opposed to a library. Executables are often called -*binaries* (as in `/usr/bin`, if you’re on a Unix system). - -Cargo has generated two files and one directory for us: a `Cargo.toml` and a -*src* directory with a *main.rs* file inside. These should look familiar, -they’re exactly what we created by hand, above. - -This output is all you need to get started. First, open `Cargo.toml`. It should -look something like this: - -```toml -[package] +So a few more differences we've now seen: -name = "hello_world" -version = "0.1.0" -authors = ["Your Name "] -``` +3. Instead of using `rustc`, build a project using `cargo build` (or build and run it in one step with `cargo run`) +4. Instead of the result of the build being put in the same directory as our code, Cargo will put it in the `target/debug` directory. -Cargo has populated *Cargo.toml* with reasonable defaults based on the arguments -you gave it and your `git` global configuration. You may notice that Cargo has -also initialized the `hello_world` directory as a `git` repository. +## Building for Release -Here’s what should be in `src/main.rs`: +When your project is finally ready for release, you can use `cargo build +--release` to compile your project with optimizations. This will create an +executable in `target/release` instead of `target/debug`. These optimizations +make your Rust code run faster, but turning them on makes your program take +longer to compile. This is why there are two different profiles: one for +development when you want to be able to rebuild quickly and often, and one for +building the final program you’ll give to a user that won't be rebuilt and +that we want to run as fast as possible. If you're benchmarking the running +time of your code, be sure to run `cargo build --release` and benchmark with +the executable in `target/release`. + +## Cargo as Convention + +With simple projects, Cargo doesn't provide a whole lot of value over just +using `rustc`, but it will prove its worth as you continue. With complex +projects composed of multiple crates, it’s much easier to let Cargo coordinate +the build. With Cargo, you can just run `cargo build`, and it should work the +right way. Even though this project is simple, it now uses much of the real +tooling you’ll use for the rest of your Rust career. In fact, you can get +started with virtually all Rust projects you might find that you want to work +on with the following commands: -```rust -fn main() { - println!("Hello, world!"); -} +```bash +$ git clone someurl.com/someproject +$ cd someproject +$ cargo build ``` -Cargo has generated a "Hello World!" for you, and you’re ready to start coding! - -> Note: If you want to look at Cargo in more detail, check out the official [Cargo -guide], which covers all of its features. +> Note: If you want to look at Cargo in more detail, check out the official +[Cargo guide], which covers all of its features. [Cargo guide]: http://doc.crates.io/guide.html From 82e8759bac8e394d8a0c00ec3ea942bf02a565bc Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 1 Aug 2016 22:34:10 -0400 Subject: [PATCH 151/204] Resolve guessing game tutorial comments Fixes #154. --- src/ch02-00-guessing-game-tutorial.md | 72 +++++++++------------------ 1 file changed, 23 insertions(+), 49 deletions(-) diff --git a/src/ch02-00-guessing-game-tutorial.md b/src/ch02-00-guessing-game-tutorial.md index 81d87794b2..e4471dd3ad 100644 --- a/src/ch02-00-guessing-game-tutorial.md +++ b/src/ch02-00-guessing-game-tutorial.md @@ -1,18 +1,14 @@ # Guessing Game -Let’s learn some Rust! For our first project, we’ll implement a classic +Let's jump into Rust with a hands-on project! We’ll implement a classic beginner programming problem: the guessing game. Here’s how it works: Our program will generate a random integer between one and a hundred. It will then prompt us to enter a guess. Upon entering our guess, it will tell us if we’re -too low or too high. Once we guess correctly, it will congratulate us. Sound -good? - +too low or too high. Once we guess correctly, it will congratulate us. ## Set up -Let’s set up a new project. Go to your projects directory. Remember the end of -the `hello world` example that mentioned `cargo new` to create new cargo -projects? Let’s give it a shot: +Let’s set up a new project. Go to your projects directory, and create a new project using Cargo. ```bash $ cd ~/projects @@ -21,7 +17,7 @@ $ cd guessing_game ``` We pass the name of our project to `cargo new`, then the `--bin` flag, since -we’re making a binary, rather than a library. +we’re going to be making another binary like in Chapter 1. Take a look at the generated `Cargo.toml`: @@ -34,10 +30,11 @@ authors = ["Your Name "] [dependencies] ``` -Cargo gets this information from your environment. If it’s not correct, go ahead -and fix that. +If the authors information that Cargo got from your environment is not correct, +go ahead and fix that. -Finally, Cargo generated a ‘Hello, world!’ for us. Check out `src/main.rs`: +And as we saw in the last chapter, `cargo new` generates a ‘Hello, world!’ for +us. Check out `src/main.rs`: ```rust fn main() { @@ -45,16 +42,7 @@ fn main() { } ``` -Let’s try compiling what Cargo gave us: - -```bash -$ cargo build - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) -``` - -Before we move on, let me show you one more Cargo command: `run`. `cargo run` -is kind of like `cargo build`, but it also then runs the produced executable. -Try it out: +Let’s try compiling what Cargo gave us and running it in the same step, using the `cargo run` command: ```bash $ cargo run @@ -101,12 +89,10 @@ use std::io; We’ll need to take user input and then print the result as output. As such, we need the `io` library from the standard library. Rust only imports a few things by default into every program, [the ‘prelude’][prelude]. If it’s not in the -prelude, you’ll have to `use` it directly. There is also a second ‘prelude’, the -[`io` prelude][ioprelude], which serves a similar function: when you import it, -you get a number of useful, `io`-related things, so that's what we've done here. +prelude, you’ll have to `use` it directly. Using the `std::io` library gets +you a number of useful `io`-related things, so that's what we've done here. [prelude]: ../std/prelude/index.html -[ioprelude]: ../std/io/prelude/index.html ```rust,ignore fn main() { @@ -114,9 +100,7 @@ fn main() { As you’ve seen in Chapter 1, the `main()` function is the entry point into the program. The `fn` syntax declares a new function, the `()`s indicate that -there are no arguments, and `{` starts the body of the function. Because -we didn’t include a return type, it’s assumed to be `()`, an empty -tuple. We will go over tuples in Chapter XX. +there are no arguments, and `{` starts the body of the function. ```rust,ignore println!("Guess the number!"); @@ -179,7 +163,7 @@ io::stdin().read_line(&mut guess) .expect("Failed to read line"); ``` -That’s a lot more! Let’s go bit-by-bit. The first line has two parts. Here’s +Let’s go through this together bit-by-bit. The first line has two parts. Here’s the first: ```rust,ignore @@ -201,10 +185,8 @@ The next part will use this handle to get input from the user: .read_line(&mut guess) ``` -Here, we call the [`read_line()`][read_line] method on our handle. Methods are -like associated functions but are only available on a particular instance of a -type, rather than the type itself. We'll talk more about methods in Chapter XX. -We’re also passing one argument to `read_line()`: `&mut guess`. +Here, we call the [`read_line()`][read_line] method on our handle. We’re also +passing one argument to `read_line()`: `&mut guess`. [read_line]: ../std/io/struct.Stdin.html#method.read_line @@ -254,9 +236,8 @@ sub-libraries, like `io::Result`. The purpose of these `Result` types is to encode error handling information. Values of the `Result` type, like any type, have methods defined on them. In this case, `io::Result` has an [`expect()` method][expect] that takes a value -it’s called on, and if it isn’t a successful one, `panic!`s with a -message you passed it. A `panic!` like this will cause our program to crash, -displaying the message. +it’s called on, and if it isn’t a successful result, will cause our program to +crash and display the message that we passed as an argument to `expect()`. [expect]: ../std/result/enum.Result.html#method.expect @@ -342,19 +323,12 @@ everything that follows the section heading is part of that section, until another section starts. Cargo uses the dependencies section to know what dependencies on external crates you have and what versions of those crates you require. In this case, we’ve specified the `rand` crate with the semantic -version specifier `0.3.14`. - -Cargo understands [Semantic Versioning][semver], which is a standard for -writing version numbers. A bare number like above is actually shorthand for -`^0.3.14`, which means "any version that has a public API compatible with -version 0.3.14". If we wanted to use only `0.3.14` exactly, we could say `rand -= "=0.3.14"` (note the equal sign within the version string). And if we wanted -to use whatever the latest version currently is, we could use `*`. [Cargo’s -documentation][cargodoc] contains more details and other ways to specify -dependencies. +version specifier `0.3.14`. Cargo understands [Semantic Versioning][semver], a +standard for writing version numbers. A bare number like above is actually +shorthand for `^0.3.14`, which means "any version that has a public API +compatible with version 0.3.14". [semver]: http://semver.org -[cargodoc]: http://doc.crates.io/specifying-dependencies.html Now, without changing any of our code, let’s build our project: @@ -770,8 +744,8 @@ fn main() { ``` And try it out. But wait, didn’t we just add an infinite loop? Yup. Remember -our discussion about `parse()`? If we give a non-number answer, we’ll `panic!` -and quit. Observe: +our discussion about `parse()`? If we give a non-number answer, the program +will crash and, therefore, quit. Observe: ```bash $ cargo run From 013e5913329704506025873c38faa5bd113355c9 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 11:07:06 -0400 Subject: [PATCH 152/204] Clarify the version of mdbook we use --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7e74f1373..c2355fdefd 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ If you would like to see this version rendered, it’s [on GitHub pages][html]. ## Requirements -Building the book requires [mdBook]. To get it: +Building the book requires [mdBook] >= v0.0.13. To get it: [mdBook]: https://github.com/azerupi/mdBook From da9d58ea0ce594e51c87bedb24c430c938104142 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 11:12:15 -0400 Subject: [PATCH 153/204] Put back code formatting inside links; works with mdbook 0.0.13 --- src/ch04-02-ownership.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch04-02-ownership.md b/src/ch04-02-ownership.md index adb1419643..b0e5b3c4ee 100644 --- a/src/ch04-02-ownership.md +++ b/src/ch04-02-ownership.md @@ -258,7 +258,7 @@ inexpensive. But what if we _do_ want to deeply copy the `String`’s data, and not just the `String` itself? There’s a common method for that: `clone()`. We will discuss -methods in the next section on [structs], but they’re a common enough feature +methods in the next section on [`structs`], but they’re a common enough feature in many programming languages that you have probably seen them before. Here’s an example of the `clone()` method in action: @@ -270,7 +270,7 @@ let s2 = s1.clone(); println!("{}", s1); ``` -[structs]: ch05-01-structs.html +[`structs`]: ch05-01-structs.html This will work just fine. Remember our diagram from before? In this case, it _is_ doing this: From fd54ef0b8558279cc4326075aebd8c2b0edbd997 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 11:15:09 -0400 Subject: [PATCH 154/204] Remove duplicated "is" from println output Fixes #164. --- src/ch03-08-loops.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch03-08-loops.md b/src/ch03-08-loops.md index 7c73efc246..f9955c75b6 100644 --- a/src/ch03-08-loops.md +++ b/src/ch03-08-loops.md @@ -151,7 +151,7 @@ fn main() { let mut index = 0; while index < 5 { - println!("the value is is: {}", a[index]); + println!("the value is: {}", a[index]); index = index + 1; } From df6105e53b6af4a42972bbdafbec222b27760069 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 11:33:56 -0400 Subject: [PATCH 155/204] Reword a case of similar wording --- src/ch04-01-ownership.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch04-01-ownership.md b/src/ch04-01-ownership.md index d6d8cb54f7..d2560e8c42 100644 --- a/src/ch04-01-ownership.md +++ b/src/ch04-01-ownership.md @@ -51,8 +51,8 @@ In other words, there are two important points in time here: - When `s` comes ‘into scope’, it is valid. - It remains so until it ‘goes out of scope’. -At this point, things are similar to other programming languages. Let’s build -on top of this understanding by introducing a new type: `String`. +At this point, things are similar to other programming languages. Now let’s +build on top of this understanding by introducing the `String` type. ## Strings From 2eb5aafc5042bd3f095a67fd16b5f457e57af9f5 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 15:40:06 -0400 Subject: [PATCH 156/204] Remove 9 exclamation marks, leave 2 that I like --- src/ch04-01-ownership.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ch04-01-ownership.md b/src/ch04-01-ownership.md index d2560e8c42..fd27258ed9 100644 --- a/src/ch04-01-ownership.md +++ b/src/ch04-01-ownership.md @@ -90,9 +90,9 @@ cannot? The difference comes down to how these two types deal with memory. In the case of a string literal, because we know the contents of the string at compile time, we can hard-code the text of the string directly into the final executable. This means that string literals are quite fast and efficient. But -these properties only come from its immutability. We can’t put a blob of memory -into the binary for each string whose size is unknown at compile time and whose -size might change over the course of running the program! +these properties only come from its immutability. Unfortunately, we can’t put a +blob of memory into the binary for each string whose size is unknown at compile +time and whose size might change over the course of running the program. With `String`, in order to support a mutable, growable string, we need to allocate an unknown amount of memory to hold the contents. This means two @@ -129,7 +129,7 @@ Rust takes a different path. Remember our example? Here’s a version with ``` We have a natural point at which we can return the memory our `String` needs -back to the operating system: when it goes out of scope! When a variable goes +back to the operating system: when it goes out of scope. When a variable goes out of scope, Rust calls a special function for us. This function is called `drop()`, and it is where the author of `String` can put the code to return the memory. @@ -141,7 +141,7 @@ memory. > is _roughly_ similar in Rust, but not identical. This pattern has a profound impact on the way that Rust code is written. It may -seem obvious right now, but things can get tricky in more advanced situations! +seem obvious right now, but things can get tricky in more advanced situations. Let’s go over the first one of those right now. ## Move @@ -153,7 +153,7 @@ let x = 5; let y = x; ``` -You might say “Make a copy of `5`.” That’d be correct! We now have two +You might say “Make a copy of `5`”, and that would be correct. We now have two bindings, `x` and `y`, and both equal `5`. Now let’s look at `String`. What would you expect this code to do? @@ -193,10 +193,10 @@ When moving, Rust makes a copy of the data structure itself. The contents of `s1` are copied, but if `s1` contains a reference, like it does in this case, Rust will not copy the things that those references refer to. -There’s a problem here! Both data pointers are pointing to the same place. Why +There’s a problem here. Both data pointers are pointing to the same place. Why is this a problem? Well, when `s2` goes out of scope, it will free the memory that the pointer points to. And then `s1` goes out of scope, and it will _also_ -try to free the memory that the pointer points to! That’s bad, and is known as +try to free the memory that the pointer points to. That’s bad, and is known as a "double free" error. So what’s the solution? Here, we stand at a crossroads with a few options. One @@ -245,7 +245,7 @@ so what actually happens looks like this: s1 and s2 to the same place With only `s2` valid, when it goes out of scope, it will free the memory, and -we’re done! +we’re done. ## Ownership Rules @@ -330,7 +330,7 @@ Here’s some types that are `Copy`: * The booleans, `true` and `false`. * All of the floating point types, like `f64`. * Tuples, but only if they contain types which are also `Copy`. `(i32, i32)` - is `Copy`, but `(i32, String)` is not! + is `Copy`, but `(i32, String)` is not. ## Ownership and functions @@ -386,7 +386,7 @@ fn makes_copy(some_integer: i32) { // some_integer comes into scope. ``` Remember: If we tried to use `s` after the call to `takes_ownership()`, Rust -would throw a compile-time error! These static checks protect us from mistakes. +would throw a compile-time error. These static checks protect us from mistakes. Try adding code to `main` that uses `s` and `x` to see where you can use them and where the ownership rules prevent you from doing so. From 9f1e9cfcc33677d0c12721a2838531bbf7a805a3 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 15:55:27 -0400 Subject: [PATCH 157/204] Rework the mention of shallow copy/deep copy Felt a bit out of place here, a little too early. --- src/ch04-01-ownership.md | 44 ++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/ch04-01-ownership.md b/src/ch04-01-ownership.md index fd27258ed9..5fb67fd9d8 100644 --- a/src/ch04-01-ownership.md +++ b/src/ch04-01-ownership.md @@ -178,10 +178,7 @@ For right now, it's fine to ignore the capacity. When we assign `s1` to `s2`, the `String` itself is copied, meaning we copy the pointer, the length, and the capacity. We do not copy the data that the -`String`'s pointer refers to. Many people draw distinctions between ‘shallow -copying’ and ‘deep copying’, and would call this a ‘shallow copy’. We don’t use -these terms in Rust; we instead say that something is ‘moved’ or ‘cloned’. -Assignment in Rust causes a ‘move’. In other words, it looks like this: +`String`'s pointer refers to. In other words, it looks like this: s1 and s2 @@ -189,10 +186,6 @@ _Not_ this: s1 and s2 to two places -When moving, Rust makes a copy of the data structure itself. The contents of -`s1` are copied, but if `s1` contains a reference, like it does in this case, -Rust will not copy the things that those references refer to. - There’s a problem here. Both data pointers are pointing to the same place. Why is this a problem? Well, when `s2` goes out of scope, it will free the memory that the pointer points to. And then `s1` goes out of scope, and it will _also_ @@ -200,17 +193,17 @@ try to free the memory that the pointer points to. That’s bad, and is known as a "double free" error. So what’s the solution? Here, we stand at a crossroads with a few options. One -would be to declare that assignment will also copy out any data. This works, -but is inefficient: what if our `String` contained a novel? Also, it only works -for memory. What if, instead of a `String`, we had a `TcpConnection`? Opening -and closing a network connection is very similar to allocating and freeing -memory, so it would be nice to be able to use the same mechanism, but we can't -because creating a new connection requires more than just copying memory: we -have to request a new connection from the operating system. The solution that -we could use there is to allow the programmer to hook into the assignment, -similar to `drop()`, and write code to fix things up. That would work, but now, -an `=` can run arbitrary code. That’s also not good, and it doesn’t solve our -efficiency concerns either. +would be to change assignment so that it will also copy out any data. This +works, but is inefficient: what if our `String` contained a novel? Also, that +solution only works for memory. What if, instead of a `String`, we had a +`TcpConnection`? Opening and closing a network connection is very similar to +allocating and freeing memory, so it would be nice to be able to use the same +mechanism. We wouldn't be able to, though, because creating a new connection +requires more than just copying memory: we have to request a new connection +from the operating system. The solution that we could use there is to allow the +programmer to hook into the assignment, similar to `drop()`, and write code to +fix things up. That would work, but if we did that, an `=` could run arbitrary +code. That’s also not good, and it doesn’t solve our efficiency concerns either. Let’s take a step back: the root of the problem is that `s1` and `s2` both think that they have control of the memory and therefore need to free it. @@ -238,14 +231,17 @@ println!("{}", s1); ^~ ``` -We say that `s1` was _moved_ into `s2`. When a value moves, its data is copied, -but the original variable binding is no longer usable. That solves our problem, -so what actually happens looks like this: +If you have heard the terms "shallow copy" and "deep copy" while working with +other languages, the concept of copying the pointer, length, and capacity +without copying the data probably sounded like a shallow copy. Because Rust +also invalidates the first binding, instead of calling this a shallow copy, +it's called a _move_. Here we would read this by saying that `s1` was _moved_ +into `s2`. So what actually happens looks like this: s1 and s2 to the same place -With only `s2` valid, when it goes out of scope, it will free the memory, and -we’re done. +That solves our problem! With only `s2` valid, when it goes out of scope, it +alone will free the memory, and we’re done. ## Ownership Rules From 0e5466135d6cafdf21c880a1127e5e64b1852594 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 16:00:13 -0400 Subject: [PATCH 158/204] Split up/reword solutioning paragraph a bit --- src/ch04-01-ownership.md | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ch04-01-ownership.md b/src/ch04-01-ownership.md index 5fb67fd9d8..b632c68fe6 100644 --- a/src/ch04-01-ownership.md +++ b/src/ch04-01-ownership.md @@ -192,18 +192,20 @@ that the pointer points to. And then `s1` goes out of scope, and it will _also_ try to free the memory that the pointer points to. That’s bad, and is known as a "double free" error. -So what’s the solution? Here, we stand at a crossroads with a few options. One -would be to change assignment so that it will also copy out any data. This -works, but is inefficient: what if our `String` contained a novel? Also, that -solution only works for memory. What if, instead of a `String`, we had a -`TcpConnection`? Opening and closing a network connection is very similar to -allocating and freeing memory, so it would be nice to be able to use the same -mechanism. We wouldn't be able to, though, because creating a new connection -requires more than just copying memory: we have to request a new connection -from the operating system. The solution that we could use there is to allow the -programmer to hook into the assignment, similar to `drop()`, and write code to -fix things up. That would work, but if we did that, an `=` could run arbitrary -code. That’s also not good, and it doesn’t solve our efficiency concerns either. +So what’s the solution? Here, we stand at a crossroads with a few options. + +One way would be to change assignment so that it will also copy out any data. +This works, but is inefficient: what if our `String` contained a novel? +Also, that solution would only work for memory. What if, instead of a `String`, +we had a `TcpConnection`? Opening and closing a network connection is very +similar to allocating and freeing memory, so it would be nice to be able to use +the same mechanism. We wouldn't be able to, though, because creating a new +connection requires more than just copying memory: we have to request a new +connection from the operating system. We could then extend our solution to +allow the programmer to hook into the assignment, similar to `drop()`, and +write code to fix things up. That would work, but if we did that, an `=` could +run arbitrary code. That’s also not good, and it doesn’t solve our efficiency +concerns either. Let’s take a step back: the root of the problem is that `s1` and `s2` both think that they have control of the memory and therefore need to free it. From 87154266d3fc9e3d9680fcab129403c5787daddc Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 16:15:39 -0400 Subject: [PATCH 159/204] Trim a bit of detail out of explanation of Copy; point to traits --- src/ch04-01-ownership.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/ch04-01-ownership.md b/src/ch04-01-ownership.md index b632c68fe6..f99d4e6399 100644 --- a/src/ch04-01-ownership.md +++ b/src/ch04-01-ownership.md @@ -306,23 +306,15 @@ there’s no difference between deep and shallow copying here, so calling we can leave it out. Rust has a special annotation that you can place on types like these, and that -annotation is called `Copy`. If a type is `Copy`, an older binding is still -usable after assignment. Integers are an example of such a type; most of the -primitive types are `Copy`. - -While we haven’t talked about how to mark a type as `Copy` yet, you might ask -yourself “what happens if we made `String` `Copy`?” The answer is you cannot. -Remember `drop()`? Rust will not let you make something `Copy` if it has +annotation is the `Copy` trait. We'll talk more about traits in Chapter XX. If +a type has the `Copy` trait, an older binding is still usable after assignment. +Rust will not let you make something have the `Copy` trait if it has implemented `drop()`. If you need to do something special when the value goes out of scope, being `Copy` will be an error. So what types are `Copy`? You can check the documentation for the given type to be sure, but as a rule of thumb, any group of simple scalar values can be Copy, -but nothing that requires allocation or is some form of resource is `Copy`. And -you can’t get it wrong: the compiler will throw an error if you incorrectly try -to use a type that moves, as we saw above. - -Here’s some types that are `Copy`: +but nothing that requires allocation or is some form of resource is `Copy`. Here’s some of the types that are `Copy`: * All of the integer types, like `u32`. * The booleans, `true` and `false`. From 32f087ef3605def7aea6d40a027c55122237260a Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 16:31:01 -0400 Subject: [PATCH 160/204] Explain matching on `&byte` a bit more --- src/ch04-03-slices.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index 99fb487fe9..b2dd7c5afb 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -55,9 +55,10 @@ a tuple instead. The first element of the tuple is the index, and the second element is a reference to the element itself. This is a bit nicer than calculating the index ourselves. -Since it’s a tuple, we can use patterns, just like elsewhere in Rust. -So we match against the tuple with i for the index and &byte for -the byte itself. +Since it’s a tuple, we can use patterns, just like elsewhere in Rust. So we +match against the tuple with i for the index and &byte for the byte itself. +Since we get a reference to a byte, we can put the `&` in the pattern, and then +the binding `byte` will hold the actual byte, not a reference to a byte. ```rust,ignore if byte == 32 { From ba95d0a22f4b011575ad1480c86c6cd7e60ac7e1 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 16:31:21 -0400 Subject: [PATCH 161/204] Wrapping --- src/ch04-03-slices.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index b2dd7c5afb..0b4906cc03 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -68,8 +68,9 @@ the binding `byte` will hold the actual byte, not a reference to a byte. s.len() ``` -We search for the value 32, which represents a space in UTF-8. If we find one, we return the -position. Otherwise, we return the length of the string, using `s.len()`. +We search for the value 32, which represents a space in UTF-8. If we find one, +we return the position. Otherwise, we return the length of the string, using +`s.len()`. This works, but there’s a problem. We’re returning a `usize` on its own, but it’s only a meaningful number in the context of the `&String`. In other From 5352d363f54741d538ffc393138e415c4f2b4680 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 16:31:29 -0400 Subject: [PATCH 162/204] Remove "same deal"-- redundant with "also" before the code --- src/ch04-03-slices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index 0b4906cc03..a7936907f1 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -201,7 +201,7 @@ This would also work for a `second_word()`: fn second_word(s: &String) -> &str { ``` -Same deal. We now have a straightforward API that’s much harder to mess up. +We now have a straightforward API that’s much harder to mess up. But what about our error condition from before? Slices also fix that. Using the slice version of `first_word()` will throw an error: From ea4ec59c50b7c8e9a3f5a5fa4784ba7ff280fd4d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 16:40:49 -0400 Subject: [PATCH 163/204] Remove hidden code until #96 is fixed --- src/ch04-03-slices.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index a7936907f1..01507f1dfa 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -207,17 +207,6 @@ But what about our error condition from before? Slices also fix that. Using the slice version of `first_word()` will throw an error: ```rust,ignore -# fn first_word(s: &String) -> &str { -# let bytes = s.as_bytes(); -# -# for (i, &byte) in bytes.iter().enumerate() { -# if byte == 32 { -# return &s[0..i]; -# } -# } -# -# &s[..] -# } fn main() { let mut s = String::from("hello world"); From 9152b70a0990c1eb96e72a5fe2aa1f3942fb66d9 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 16:41:49 -0400 Subject: [PATCH 164/204] Use bash syntax highlighting for error message output --- src/ch04-03-slices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index 01507f1dfa..2f316384e5 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -218,7 +218,7 @@ fn main() { Here’s the error: -```text +```bash 17:6 error: cannot borrow `s` as mutable because it is also borrowed as immutable [E0502] s.clear(); // Error! From 8e5bba01d663417e3494d58a51149b0aa834f94a Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 17:01:48 -0400 Subject: [PATCH 165/204] Clarify this code sample with less shadowing and more comments --- src/ch04-03-slices.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index 2f316384e5..28d962799c 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -288,13 +288,19 @@ with no loss of functionality: # &s[..] # } fn main() { - let s = String::from("hello world"); - let word = first_word(&s[..]); + let my_string = String::from("hello world"); - let s = "hello world"; - let word = first_word(&s[..]); + // first_word works on slices of `String`s + let word = first_word(&my_string[..]); - let word = first_word(s); // since literals are &strs, this works too! + let my_string_literal = "hello world"; + + // first_word works on slices of string literals + let word = first_word(&my_string_literal[..]); + + // since string literals *are* string slices already, + // this works too, without the slice syntax! + let word = first_word(my_string_literal); } ``` From d61336d619a04bb76af70943446f808693a328da Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 17:07:34 -0400 Subject: [PATCH 166/204] Switch out `item` for `byte` to avoid overloading `byte` --- src/ch04-03-slices.md | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index 28d962799c..f098485deb 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -24,8 +24,8 @@ the word, though. Let’s try that: fn first_word(s: &String) -> usize { let bytes = s.as_bytes(); - for (i, &byte) in bytes.iter().enumerate() { - if byte == 32 { + for (i, &item) in bytes.iter().enumerate() { + if item == 32 { return i; } } @@ -45,7 +45,7 @@ check if a value is a space, we will convert our String to an array of bytes using the `.as_bytes()` method. ```rust,ignore -for (i, &byte) in bytes.iter().enumerate() { +for (i, &item) in bytes.iter().enumerate() { ``` We will be discussing iterators in more detail in Chapter XX, but for @@ -56,12 +56,11 @@ second element is a reference to the element itself. This is a bit nicer than calculating the index ourselves. Since it’s a tuple, we can use patterns, just like elsewhere in Rust. So we -match against the tuple with i for the index and &byte for the byte itself. -Since we get a reference to a byte, we can put the `&` in the pattern, and then -the binding `byte` will hold the actual byte, not a reference to a byte. +match against the tuple with i for the index and &item for a single byte. Since +we get a reference from `.iter().enumerate()`, we use `&` in the pattern. ```rust,ignore - if byte == 32 { + if item == 32 { return i; } } @@ -81,8 +80,8 @@ that it will still be valid in the future. Consider this: # fn first_word(s: &String) -> usize { # let bytes = s.as_bytes(); # -# for (i, &byte) in bytes.iter().enumerate() { -# if byte == 32 { +# for (i, &item) in bytes.iter().enumerate() { +# if item == 32 { # return i; # } # } @@ -181,8 +180,8 @@ With this in mind, let’s re-write `first_word()` to return a slice: fn first_word(s: &String) -> &str { let bytes = s.as_bytes(); - for (i, &byte) in bytes.iter().enumerate() { - if byte == 32 { + for (i, &item) in bytes.iter().enumerate() { + if item == 32 { return &s[0..i]; } } @@ -279,8 +278,8 @@ with no loss of functionality: # fn first_word(s: &str) -> &str { # let bytes = s.as_bytes(); # -# for (i, &byte) in bytes.iter().enumerate() { -# if byte == 32 { +# for (i, &item) in bytes.iter().enumerate() { +# if item == 32 { # return &s[0..i]; # } # } From b5d45f13c6e13515a6195d29af2545881f3f128b Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 17:11:24 -0400 Subject: [PATCH 167/204] Switch struct to singular to avoid weird `struct`s formatting --- src/ch05-00-structs.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ch05-00-structs.md b/src/ch05-00-structs.md index 75691a7d70..82a6719a34 100644 --- a/src/ch05-00-structs.md +++ b/src/ch05-00-structs.md @@ -1,12 +1,11 @@ # Structs -`struct`s, short for "structures", give us the ability to name and package +A `struct`, short for "structure", gives us the ability to name and package together multiple related values that make up a meaningful group. If you come -from an object-oriented language, `struct`s are like an object's data -attributes. `structs`, along with `enum`s that we talked about in the last -chapter, are the building blocks you can use in Rust to create new types in -your program's domain in order to take full advantage of Rust's compile-time -type checking. +from an object-oriented language, a `struct` is like an object's data +attributes. `struct` and `enum` (that we talked about in the last chapter) are +the building blocks you can use in Rust to create new types in your program's +domain in order to take full advantage of Rust's compile-time type checking. Let’s write a program which calculates the distance between two points. We’ll start off with single variable bindings, and then refactor it to From 54dc57cef3bac2f46eb18bdf7e0225f6c52341c6 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 17:22:22 -0400 Subject: [PATCH 168/204] Remove pseudo-EBNF, just refer to example in prose --- src/ch05-00-structs.md | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/ch05-00-structs.md b/src/ch05-00-structs.md index 82a6719a34..f15f1bed5d 100644 --- a/src/ch05-00-structs.md +++ b/src/ch05-00-structs.md @@ -148,16 +148,10 @@ struct Point { let p1 = Point { x: 0.0, y: 5.0 }; ``` -Here’s what declaring a `struct` looks like in general: - -```text -struct NAME { - NAME: TYPE, -} -``` - -The `NAME: TYPE` bit is called a ‘field’, and we can have as many or as few of -them as we’d like. +Here we've defined a `struct` and given it the name `Point`. The parts inside +`{}` are defining the _fields_ of the struct. We can have as many or as few of +them as we'd like, and we give them a name and specify their type. Here we have +two fields named `x` and `y`, and they both hold `f64`s. We can access the field of a struct in the same way we access an element of a tuple, except we use its name: From 3a6d94125964fe7e37e3cabd03a5f9cb8609ff6c Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 17:36:38 -0400 Subject: [PATCH 169/204] Wording, typos, formatting edits to method syntax --- src/ch05-01-method-syntax.md | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/ch05-01-method-syntax.md b/src/ch05-01-method-syntax.md index ef4cb6ac6a..4d97018b85 100644 --- a/src/ch05-01-method-syntax.md +++ b/src/ch05-01-method-syntax.md @@ -27,8 +27,9 @@ h(g(f(x))); x.f().g().h(); ``` -The nested-functions version reads in reverse: we call `f()`, then `g()`, then -`h()`, but it reads as `h()`, then `g()`, then `f()`. +The nested-functions version reads in reverse: the program executes `f()`, then +`g()`, then `h()`, but we read it left-to-right as `h()`, then `g()`, then +`f()`. The method syntax is executed in the same order as we would read it. Before we get into the details, let’s talk about how to define your own methods. @@ -124,19 +125,22 @@ fn distance(p1: Point, p2: Point) -> f64 { # let y_squared = f64::powi(p2.y - p1.y, 2); # # f64::sqrt(x_squared + y_squared) -# } +} ``` Other than this, the rest of the example is familiar: an implementation of -`distance()`, and using the method to find an answer. +`distance()` and using the method to find an answer. + +There are two differences in the definitions. The first is in the first +argument. Instead of a name and a type, we have written `&self`. This is what +distinguishes a method from a function: using `self` inside of an `impl` block +means we have a method. Because we already know that we are implementing this +method on `Point` because of the surrounding `impl Point` block, we don’t need +to write the type of `self` out. -There are two differences. The first is in the first argument. Instead of a name -and a type, we have written `&self`. This is what distinguishes a method from a -function: using `self` inside of an `impl` block. Because we already know that -we are implementing this method on `Point`, we don’t need to write the type of -`self` out. However, we have written `&self`, not only `self`. This is because -we want to take our argument by reference rather than by ownership. In other -words, these two forms are the same: +Note that we have written `&self`, not just `self`. This is because we want to +take a reference to our argument's value rather than taking ownership of it. In +other words, these two forms are the same: ```rust,ignore fn foo(self: &Point) @@ -152,10 +156,12 @@ fn foo(&mut self) // take self by mutable reference fn foo(self) // take self by ownership ``` -In this case, we only need a reference. We don’t plan on taking ownership, and -we don’t need to mutate either point. Taking by reference is by far the most -common form of method, followed by a mutable reference, and then occasionally -by ownership. +In this case, we only need a reference. We don’t need to mutate either `Point` +to get the distance between them, so we won't take a mutable reference to the +`Point` that we call the method on. Methods that take ownership of `self` are +rarely used. An example of a time to do that would be if we wanted to have a +method that would transform `self` into something else and prevent other code +from using the value of `self` after the transformation happens. ### Methods and automatic referencing From 723852ebb8e7bbcb31a3db24318aefca8d880d1b Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 17:45:58 -0400 Subject: [PATCH 170/204] Remove a bunch of repeated hidden code This is all exactly the same as the first code block, so it is still being tested. It looks weird with the indenting when the code is hidden, and it's harder for me to read when editing the src (but I will leave hidden code in if it lets us test unique code examples) --- src/ch05-01-method-syntax.md | 76 +++++------------------------------- 1 file changed, 9 insertions(+), 67 deletions(-) diff --git a/src/ch05-01-method-syntax.md b/src/ch05-01-method-syntax.md index 4d97018b85..a406a2011f 100644 --- a/src/ch05-01-method-syntax.md +++ b/src/ch05-01-method-syntax.md @@ -64,67 +64,27 @@ assert_eq!(8.200609733428363, p1.distance(&p2)); Let’s break this down. First, we have our `Point` struct from earlier in the chapter. Next comes our first use of the `impl` keyword: -``` -# #[derive(Debug,Copy,Clone)] -# struct Point { -# x: f64, -# y: f64, -# } -# +```rust,ignore impl Point { -# fn distance(&self, other: &Point) -> f64 { -# let x_squared = f64::powi(other.x - self.x, 2); -# let y_squared = f64::powi(other.y - self.y, 2); -# -# f64::sqrt(x_squared + y_squared) -# } + // ... } -# -# let p1 = Point { x: 0.0, y: 0.0 }; -# let p2 = Point { x: 5.0, y: 6.5 }; -# -# assert_eq!(8.200609733428363, p1.distance(&p2)); ``` Everything we put inside of the curly braces will be methods implemented on `Point`. -``` -# #[derive(Debug,Copy,Clone)] -# struct Point { -# x: f64, -# y: f64, -# } -# -# impl Point { - fn distance(&self, other: &Point) -> f64 { -# let x_squared = f64::powi(other.x - self.x, 2); -# let y_squared = f64::powi(other.y - self.y, 2); -# -# f64::sqrt(x_squared + y_squared) - } -# } -# -# let p1 = Point { x: 0.0, y: 0.0 }; -# let p2 = Point { x: 5.0, y: 6.5 }; -# -# assert_eq!(8.200609733428363, p1.distance(&p2)); +```rust,ignore +fn distance(&self, other: &Point) -> f64 { + // ... +} ``` Next is our definition. This looks very similar to our previous definition of `distance()` as a function: -```rust -# #[derive(Debug,Copy,Clone)] -# struct Point { -# x: f64, -# y: f64, -# } +```rust,ignore fn distance(p1: Point, p2: Point) -> f64 { -# let x_squared = f64::powi(p2.x - p1.x, 2); -# let y_squared = f64::powi(p2.y - p1.y, 2); -# -# f64::sqrt(x_squared + y_squared) + // ... } ``` @@ -167,25 +127,7 @@ from using the value of `self` after the transformation happens. We’ve left out an important detail. It’s in this line of the example: -``` -# #[derive(Debug,Copy,Clone)] -# struct Point { -# x: f64, -# y: f64, -# } -# -# impl Point { -# fn distance(&self, other: &Point) -> f64 { -# let x_squared = f64::powi(other.x - self.x, 2); -# let y_squared = f64::powi(other.y - self.y, 2); -# -# f64::sqrt(x_squared + y_squared) -# } -# } -# -# let p1 = Point { x: 0.0, y: 0.0 }; -# let p2 = Point { x: 5.0, y: 6.5 }; -# +```rust,ignore assert_eq!(8.200609733428363, p1.distance(&p2)); ``` From bfc469d83a0a1aca52168cedb881e02bf0ce1e81 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 17:47:28 -0400 Subject: [PATCH 171/204] Clarify what's coming from which example --- src/ch05-01-method-syntax.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ch05-01-method-syntax.md b/src/ch05-01-method-syntax.md index a406a2011f..854d1eb46c 100644 --- a/src/ch05-01-method-syntax.md +++ b/src/ch05-01-method-syntax.md @@ -71,7 +71,7 @@ impl Point { ``` Everything we put inside of the curly braces will be methods implemented on -`Point`. +`Point`. Next is our definition: ```rust,ignore fn distance(&self, other: &Point) -> f64 { @@ -79,8 +79,12 @@ fn distance(&self, other: &Point) -> f64 { } ``` -Next is our definition. This looks very similar to our previous definition of -`distance()` as a function: +Other than this, the rest of the example is familiar: an implementation of +`distance()` and using the method to find an answer. + +Our definition of `distance()` here as a method looks very similar to our +previous definition of `distance()` as a function, but with two differences. +Here's the `distance()` function again: ```rust,ignore fn distance(p1: Point, p2: Point) -> f64 { @@ -88,15 +92,11 @@ fn distance(p1: Point, p2: Point) -> f64 { } ``` -Other than this, the rest of the example is familiar: an implementation of -`distance()` and using the method to find an answer. - -There are two differences in the definitions. The first is in the first -argument. Instead of a name and a type, we have written `&self`. This is what -distinguishes a method from a function: using `self` inside of an `impl` block -means we have a method. Because we already know that we are implementing this -method on `Point` because of the surrounding `impl Point` block, we don’t need -to write the type of `self` out. +The first difference is in the first argument. Instead of a name and a type, we +have written `&self`. This is what distinguishes a method from a function: +using `self` inside of an `impl` block means we have a method. Because we +already know that we are implementing this method on `Point` because of the +surrounding `impl Point` block, we don’t need to write the type of `self` out. Note that we have written `&self`, not just `self`. This is because we want to take a reference to our argument's value rather than taking ownership of it. In From e6443565ebc7c71d549226debb7e1d9a3e3812a8 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 17:56:34 -0400 Subject: [PATCH 172/204] Use a string literal instead of `String::from`; that's not a method We've talked about Strings vs string literals at this point. Hopefully this should be less distracting. --- src/ch05-01-method-syntax.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ch05-01-method-syntax.md b/src/ch05-01-method-syntax.md index 854d1eb46c..74ec4f9955 100644 --- a/src/ch05-01-method-syntax.md +++ b/src/ch05-01-method-syntax.md @@ -4,9 +4,9 @@ In the last section on ownership, we made several references to ‘methods’. Methods look like this: ```rust -let s1 = String::from("hello"); +let s1 = "hello"; -// call a method on our String +// call a method on s1 let s2 = s1.clone(); println!("{}", s1); From b9254d86b0358de77013874658967a0a1f8e6a38 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 18:04:00 -0400 Subject: [PATCH 173/204] Remove a confusing section on calling methods like functions --- src/ch05-01-method-syntax.md | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/src/ch05-01-method-syntax.md b/src/ch05-01-method-syntax.md index 74ec4f9955..aeef89529b 100644 --- a/src/ch05-01-method-syntax.md +++ b/src/ch05-01-method-syntax.md @@ -187,38 +187,3 @@ of a method whether the method is just reading (so needs `&self`), mutating (so `&mut self`), or consuming (so `self`). The fact that Rust makes borrowing implicit for method receivers is a big part of making ownership ergonomic in practice. - -## Methods can be called like functions - -Furthermore, if we have a method, we can also call it like a function: - -```rust -# #[derive(Debug,Copy,Clone)] -# struct Point { -# x: f64, -# y: f64, -# } -# -# impl Point { -# fn distance(&self, other: &Point) -> f64 { -# let x_squared = f64::powi(other.x - self.x, 2); -# let y_squared = f64::powi(other.y - self.y, 2); -# -# f64::sqrt(x_squared + y_squared) -# } -# } -# let p1 = Point { x: 0.0, y: 0.0 }; -# let p2 = Point { x: 5.0, y: 6.5 }; -let d1 = p1.distance(&p2); -let d2 = Point::distance(&p1, &p2); - -assert_eq!(d1, d2); -``` - -Instead of using `self.(`, we use `Point` and the namespace operator to call it -like a function instead. Because functions do not do the automatic referencing, -we must pass in `&p1` explicitly. - -While methods can be called like functions, functions cannot be called like -methods. If the first argument isn’t named `self`, it cannot be called like a -method. From 5fb0b5364834d5bb1f4f0c5cf20f5916172a5f5a Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 20:32:48 -0400 Subject: [PATCH 174/204] Move generics to its own chapter outside of the first third --- src/ch05-03-generics.md => chZZ-generics.md | 0 src/SUMMARY.md | 2 ++ 2 files changed, 2 insertions(+) rename src/ch05-03-generics.md => chZZ-generics.md (100%) diff --git a/src/ch05-03-generics.md b/chZZ-generics.md similarity index 100% rename from src/ch05-03-generics.md rename to chZZ-generics.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 1edbc1468d..aceed74ae9 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -42,6 +42,8 @@ - [Lifetimes]() +- [Generics](chZZ-generics.md) + - [Traits]() - [Closures]() From 18a1411a5d7d3c0d6055ae949a56390ce0c46f84 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 20:34:55 -0400 Subject: [PATCH 175/204] Oops, messed up that rename somehow... --- src/chZZ-generics.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/chZZ-generics.md diff --git a/src/chZZ-generics.md b/src/chZZ-generics.md new file mode 100644 index 0000000000..292d26b987 --- /dev/null +++ b/src/chZZ-generics.md @@ -0,0 +1 @@ +# Generics From b817838ea9e36229e7c6bb9e3f8a84e644d24f5b Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 20:37:08 -0400 Subject: [PATCH 176/204] Uhhh messed it up again --- chZZ-generics.md | 192 ------------------------------------------- src/chZZ-generics.md | 191 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+), 192 deletions(-) delete mode 100644 chZZ-generics.md diff --git a/chZZ-generics.md b/chZZ-generics.md deleted file mode 100644 index eab0646967..0000000000 --- a/chZZ-generics.md +++ /dev/null @@ -1,192 +0,0 @@ -# Generics - -We've been working with a `Point` struct that looks like this: - -```rust -#[derive(Debug,Copy,Clone)] -struct Point { - x: f64, - y: f64, -} -``` - -But what if we didn't want to always use an `f64` here? What about an `f32` for -when we need less precision? Or an `i32` if we only want integer coordinates? - -While our simple `Point` struct may be a bit too simple to bother making -generic in a real application, we're going to stick with it to show you the -syntax. Especially when building library code, generics allow for more code -re-use, and unlock a lot of powerful techniques. - -## Generic data types - -'Generics' let us write code that allows for several different types, while -letting us have one definition. A more generic `Point` would look like this: - -```rust -#[derive(Debug,Copy,Clone)] -struct Point { - x: T, - y: T, -} -``` - -There are two changes here, and they both involve this new `T`. The first change -is in the definition: - -```rust -# #[derive(Debug,Copy,Clone)] -struct Point { -# x: T, -# y: T, -# } -``` - -Our previous definition said, "We are defining a struct named Point." This -definition says something slightly different: "We are defining a struct named -Point with one type parameter `T`." - -Let's talk about this term 'type parameter'. We've already seen one other thing -called a 'parameter' in Rust: function parameters: - -```rust -fn plus_one(x: i32) -> i32 { - x + 1 -} -``` - -Here, `x` is a parameter to this function. We can call this function with a -different value, and `x` will change each time it's called: - -```rust -# fn plus_one(x: i32) -> i32 { -# x + 1 -# } -let six = plus_one(5); -let eleven = plus_one(10); -``` - -In the same way, a type parameter allows us to define a data type which can be -different each time we use it: - -```rust -#[derive(Debug,Copy,Clone)] -struct Point { - x: T, - y: T, -} - -let integral_point = Point { x: 5, y: 5 }; -let floating_point = Point { x: 5.0, y: 5.0 }; -``` - -Here, `integral_point` uses `i32` values for `T`, and `floating_point` uses -`f64` values. This also leads us to talk about the second change we made to `Point`: - -```rust -# #[derive(Debug,Copy,Clone)] -# struct Point { - x: T, - y: T, -# } -``` - -Instead of saying `x: i32`, we say `x: T`. This `T` is the same one that we -used above in the struct declaration. Because `x` and `y` both use `T`, they'll -be the same type. We could give them different types: - -```rust -#[derive(Debug,Copy,Clone)] -struct Point { - x: T, - y: OtherT, -} - -let different = Point { x: 5, y: 5.0 }; -let same = Point { x: 5.0, y: 5.0 }; -``` - -Here, instead of a single parameter, `T`, we have two: `T` and `OtherT`. Type -parameters have the same naming convention as other types: `CamelCase`. -However, you'll often see short, one-letter names used for types. `T` is very -common, because it's short for 'type', but you can name them something longer -if you'd like. In this version of `Point`, we say that `x` has the type `T`, -and `y` has the type `OtherT`. This lets us give them two different types, but -they don't have to be. - -## Generic functions - -Regular old functions can also take generic parameters, with a syntax that looks -very similar: - -```rust -fn foo(x: T) { - // ... -} -``` - -This `foo()` function has one generic parameter, `T`, and takes one argument, -`x`, which has the type `T`. Let's talk a little bit more about what this means. - - -## Generic methods - -We've seen how to define methods with the `impl` keyword. Our generic `Point` -can have generic methods, too: - -```rust -#[derive(Debug,Copy,Clone)] -struct Point { - x: T, - y: T, -} - -impl Point { - fn some_method(&self) { - // ... - } -} -``` - -We also need the `` after `impl`. This line reads, "We will be implementing -methods with one generic type parameter, `T`, for a type, `Point`, which takes -one generic type `T`." In a sense, the `impl` says "we will be using a type -`T`" and the `Point` says "that `T` is used for `Point`." In this simple -case, this syntax can feel a bit redundant, but when we get into some of Rust's -more advanced features later, this distinction will become more useful. - -## There's more to the story - -This section covered the basic syntax of generics, but it's not the full story. -For example, let's try to implement our `foo()` function: we'll have it print out -the value of `x`: - -```rust,ignore -fn foo(x: T) { - println!("x is: {}", x); -} -``` - -We'll get an error: - -```text -error: the trait `core::fmt::Display` is not implemented for the type `T` [E0277] -println!("x is: {}", x); - ^ -``` - -We can't print out `x`! The error messages reference something we talked about -briefly before, the `Display` trait. In order to implement this function, we -need to talk about traits. But we only need to talk about traits to implement -our own generic functions; we don't need this understanding to use them. So -rather than get into more details about this right now, let's talk about other -useful Rust data types, and we can come back to implementing generic functions -in the chapter about traits. - -For now, the important bits to understand: - -* Generic type parameters are kind of like function parameters, but for types - instead of values. -* Type parameters go inside `<>`s and are usually named things like `T`. - -With that, let's talk about another fundamental Rust data type: enums. diff --git a/src/chZZ-generics.md b/src/chZZ-generics.md index 292d26b987..eab0646967 100644 --- a/src/chZZ-generics.md +++ b/src/chZZ-generics.md @@ -1 +1,192 @@ # Generics + +We've been working with a `Point` struct that looks like this: + +```rust +#[derive(Debug,Copy,Clone)] +struct Point { + x: f64, + y: f64, +} +``` + +But what if we didn't want to always use an `f64` here? What about an `f32` for +when we need less precision? Or an `i32` if we only want integer coordinates? + +While our simple `Point` struct may be a bit too simple to bother making +generic in a real application, we're going to stick with it to show you the +syntax. Especially when building library code, generics allow for more code +re-use, and unlock a lot of powerful techniques. + +## Generic data types + +'Generics' let us write code that allows for several different types, while +letting us have one definition. A more generic `Point` would look like this: + +```rust +#[derive(Debug,Copy,Clone)] +struct Point { + x: T, + y: T, +} +``` + +There are two changes here, and they both involve this new `T`. The first change +is in the definition: + +```rust +# #[derive(Debug,Copy,Clone)] +struct Point { +# x: T, +# y: T, +# } +``` + +Our previous definition said, "We are defining a struct named Point." This +definition says something slightly different: "We are defining a struct named +Point with one type parameter `T`." + +Let's talk about this term 'type parameter'. We've already seen one other thing +called a 'parameter' in Rust: function parameters: + +```rust +fn plus_one(x: i32) -> i32 { + x + 1 +} +``` + +Here, `x` is a parameter to this function. We can call this function with a +different value, and `x` will change each time it's called: + +```rust +# fn plus_one(x: i32) -> i32 { +# x + 1 +# } +let six = plus_one(5); +let eleven = plus_one(10); +``` + +In the same way, a type parameter allows us to define a data type which can be +different each time we use it: + +```rust +#[derive(Debug,Copy,Clone)] +struct Point { + x: T, + y: T, +} + +let integral_point = Point { x: 5, y: 5 }; +let floating_point = Point { x: 5.0, y: 5.0 }; +``` + +Here, `integral_point` uses `i32` values for `T`, and `floating_point` uses +`f64` values. This also leads us to talk about the second change we made to `Point`: + +```rust +# #[derive(Debug,Copy,Clone)] +# struct Point { + x: T, + y: T, +# } +``` + +Instead of saying `x: i32`, we say `x: T`. This `T` is the same one that we +used above in the struct declaration. Because `x` and `y` both use `T`, they'll +be the same type. We could give them different types: + +```rust +#[derive(Debug,Copy,Clone)] +struct Point { + x: T, + y: OtherT, +} + +let different = Point { x: 5, y: 5.0 }; +let same = Point { x: 5.0, y: 5.0 }; +``` + +Here, instead of a single parameter, `T`, we have two: `T` and `OtherT`. Type +parameters have the same naming convention as other types: `CamelCase`. +However, you'll often see short, one-letter names used for types. `T` is very +common, because it's short for 'type', but you can name them something longer +if you'd like. In this version of `Point`, we say that `x` has the type `T`, +and `y` has the type `OtherT`. This lets us give them two different types, but +they don't have to be. + +## Generic functions + +Regular old functions can also take generic parameters, with a syntax that looks +very similar: + +```rust +fn foo(x: T) { + // ... +} +``` + +This `foo()` function has one generic parameter, `T`, and takes one argument, +`x`, which has the type `T`. Let's talk a little bit more about what this means. + + +## Generic methods + +We've seen how to define methods with the `impl` keyword. Our generic `Point` +can have generic methods, too: + +```rust +#[derive(Debug,Copy,Clone)] +struct Point { + x: T, + y: T, +} + +impl Point { + fn some_method(&self) { + // ... + } +} +``` + +We also need the `` after `impl`. This line reads, "We will be implementing +methods with one generic type parameter, `T`, for a type, `Point`, which takes +one generic type `T`." In a sense, the `impl` says "we will be using a type +`T`" and the `Point` says "that `T` is used for `Point`." In this simple +case, this syntax can feel a bit redundant, but when we get into some of Rust's +more advanced features later, this distinction will become more useful. + +## There's more to the story + +This section covered the basic syntax of generics, but it's not the full story. +For example, let's try to implement our `foo()` function: we'll have it print out +the value of `x`: + +```rust,ignore +fn foo(x: T) { + println!("x is: {}", x); +} +``` + +We'll get an error: + +```text +error: the trait `core::fmt::Display` is not implemented for the type `T` [E0277] +println!("x is: {}", x); + ^ +``` + +We can't print out `x`! The error messages reference something we talked about +briefly before, the `Display` trait. In order to implement this function, we +need to talk about traits. But we only need to talk about traits to implement +our own generic functions; we don't need this understanding to use them. So +rather than get into more details about this right now, let's talk about other +useful Rust data types, and we can come back to implementing generic functions +in the chapter about traits. + +For now, the important bits to understand: + +* Generic type parameters are kind of like function parameters, but for types + instead of values. +* Type parameters go inside `<>`s and are usually named things like `T`. + +With that, let's talk about another fundamental Rust data type: enums. From 1f0afd63ad0b3b899af7e8e79dba8e409fe539f0 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 20:38:12 -0400 Subject: [PATCH 177/204] Aha now I see that I forgot to remove the old chapter from summary --- src/SUMMARY.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index aceed74ae9..9fdd6cb8e1 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -23,7 +23,6 @@ - [Structs](ch05-01-structs.md) - [Method Syntax](ch05-02-method-syntax.md) - - [Generics](ch05-03-generics.md) - [Advanced]() - [Enums](ch06-01-enums.md) From 52b8d776c3ef42e59972a390c303d3aa2f099c71 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 20:43:09 -0400 Subject: [PATCH 178/204] Update error message for line numbers Fixes #172. --- src/ch03-01-variable-bindings-and-mutability.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch03-01-variable-bindings-and-mutability.md b/src/ch03-01-variable-bindings-and-mutability.md index 0649b8eaa6..8854ca855e 100644 --- a/src/ch03-01-variable-bindings-and-mutability.md +++ b/src/ch03-01-variable-bindings-and-mutability.md @@ -36,7 +36,7 @@ $ cargo run Compiling bindings v0.0.1 (file:///projects/bindings) error: re-assignment of immutable variable `x` [--explain E0384] --> src/main.rs:4:5 -3 |> x = 6; +4 |> x = 6; |> ^^^^^ note: prior assignment occurs here --> src/main.rs:2:9 From f47d7cd80c9cbe4c16f180069af54826ac4b4c29 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 20:56:12 -0400 Subject: [PATCH 179/204] "arity" isn't really relevant --- src/ch03-02-data-types.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ch03-02-data-types.md b/src/ch03-02-data-types.md index 796a3320b4..b98f3d9e43 100644 --- a/src/ch03-02-data-types.md +++ b/src/ch03-02-data-types.md @@ -169,8 +169,7 @@ has two primitive compound types: tuples and arrays. We’ve seen tuples already, when binding multiple values at once. A tuple is a general way of grouping together some number of other values with distinct -types into one compound type. The number of values is called the *arity* of the -tuple. +types into one compound type. We create a tuple by writing a comma-separated list of values inside parentheses. Each position in the tuple has a distinct type, as in this example: From b3c3483e698376a732a41b8f0a7bed60446c2cf1 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 20:56:29 -0400 Subject: [PATCH 180/204] Update section header since we took modifying out --- src/ch03-02-data-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch03-02-data-types.md b/src/ch03-02-data-types.md index b98f3d9e43..9025a9f842 100644 --- a/src/ch03-02-data-types.md +++ b/src/ch03-02-data-types.md @@ -246,7 +246,7 @@ by the standard library that _is_ allowed to grow or shrink in size. If you're unsure whether to use an array or a `Vec`, you should probably go with a `Vec`, and we'll discuss them in more detail in chapter XX. -#### Accessing and Modifying Array Elements +#### Accessing Array Elements An array is a single chunk of memory, allocated on the stack. We can access elements of an array using indexing, like this: From 9b92a4e0cb5a8c3356cde21228cff4a9497879df Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 21:03:49 -0400 Subject: [PATCH 181/204] Simplify discussion of function arguments --- src/ch03-03-how-functions-work.md | 36 ++++++------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/src/ch03-03-how-functions-work.md b/src/ch03-03-how-functions-work.md index 99ab25b7b7..7a724576e8 100644 --- a/src/ch03-03-how-functions-work.md +++ b/src/ch03-03-how-functions-work.md @@ -83,40 +83,18 @@ The value of x is: 5 ``` Since we passed `5` to `another_function()`, the `println!` macro put `5` where -the pair of curly braces were in the format string. +the pair of curly braces were in the format string. The declaration of +`another_function()` shows that it takes one argument named `x`, and the type +of `x` is `i32`. -Let’s take a closer look at the signature of a function which takes a single -argument: - -```text -fn NAME(PATTERN: TYPE) { -``` - -The parameter declaration in a single-argument function signature looks like -the `let` bindings we used earlier in the "Type Inference and Annotation" -section. Just look at both together, and compare them: - -```rust,ignore -let x: i32; -fn another_function(x: i32) { -``` - -The one difference is that in function signatures, we _must_ declare the type. -This is a deliberate decision in the design of Rust; requiring type annotations -in function definitions means the compiler almost never needs you to use them -elsewhere in the code in order to figure out what you mean. +In function signatures, we _must_ declare the type. This is a deliberate +decision in the design of Rust; requiring type annotations in function +definitions means the compiler almost never needs you to use them elsewhere in +the code in order to figure out what you mean. When you want a function to have multiple arguments, just separate them inside the function signature with commas, like this: -```text -fn NAME(PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE...) { -``` - -And just like a `let` declaration with multiple patterns, a type must be -applied to each pattern separately. To demonstrate, here’s a full example of a -function with multiple arguments: - ```rust fn main() { another_function(5, 6); From 12436d7ed5979c9169d32475352a2affbfa16479 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 21:07:41 -0400 Subject: [PATCH 182/204] Rework return types to not need the pseudo-EBNF either --- src/ch03-03-how-functions-work.md | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/ch03-03-how-functions-work.md b/src/ch03-03-how-functions-work.md index 7a724576e8..3a1c9856bf 100644 --- a/src/ch03-03-how-functions-work.md +++ b/src/ch03-03-how-functions-work.md @@ -228,35 +228,22 @@ value. Keep this in mind as we explore function return values and expressions. ### Functions with Return Values -Functions can return values back to the code that calls them. In Rust, the -"return value of the function” is synonymous with “the value of the final -expression in the block of the body of a function.” A function that returns a -value looks like this: - -```text -fn NAME(PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE...) -> TYPE { - STATEMENT* - EXPRESSION -} -``` - -The `*` by `STATEMENT` indicates "zero or more", meaning we can have any number -of statements inside the function body block, ending with an expression since -we are returning a value. - -In Rust, we don’t name return values, but we do declare their type, after an -arrow (`->`). Here’s a sample program to illustrate this concept: +Functions can return values back to the code that calls them. We don’t name +return values, but we do declare their type, after an arrow (`->`). In Rust, +the "return value of the function” is synonymous with “the value of the final +expression in the block of the body of a function.” Here's an example of a +function that returns a value: ```rust +fn five() -> i32 { + 5 +} + fn main() { let x = five(); println!("The value of x is: {}", x); } - -fn five() -> i32 { - 5 -} ``` There are no function calls, macros, or even `let` statements in the `five()` From 76667ad23802fb4f3e7e4b3dbcd01a4159ee0e14 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 21:10:39 -0400 Subject: [PATCH 183/204] Update error messages --- src/ch03-03-how-functions-work.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/ch03-03-how-functions-work.md b/src/ch03-03-how-functions-work.md index 3a1c9856bf..b5f1e68056 100644 --- a/src/ch03-03-how-functions-work.md +++ b/src/ch03-03-how-functions-work.md @@ -167,10 +167,12 @@ If we were to run this program, we’d get an error like this: ```bash $ cargo run Compiling functions v0.1.0 (file:///projects/functions) -src/main.rs:2:14: 2:17 error: expected expression, found statement (`let`) -src/main.rs:2 let x = (let y = 6); - ^~~ -src/main.rs:2:14: 2:17 note: variable declaration using `let` is a statement +error: expected expression, found statement (`let`) + --> src/main.rs:2:14 +2 |> let x = (let y = 6); + |> ^^^ +note: variable declaration using `let` is a statement + error: aborting due to previous error error: Could not compile `functions`. ``` @@ -307,13 +309,15 @@ Running this code gives an error, as follows: ```bash $ cargo run Compiling functions v0.1.0 (file:///projects/functions) -src/main.rs:7:1: 9:2 error: not all control paths return a value [E0269] -src/main.rs:7 fn plus_one(x: i32) -> i32 { - ^ -src/main.rs:7:1: 9:2 help: run `rustc --explain E0269` to see a detailed explanation -src/main.rs:8:10: 8:11 help: consider removing this semicolon: -src/main.rs:8 x + 1; - ^ +error: not all control paths return a value [--explain E0269] + --> src/main.rs:7:1 +7 |> fn plus_one(x: i32) -> i32 { + |> ^ +help: consider removing this semicolon: + --> src/main.rs:8:10 +8 |> x + 1; + |> ^ + error: aborting due to previous error error: Could not compile `functions`. ``` From e399e84b22d5f2d18600462ba7e78d0e7bc9208f Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 21:27:26 -0400 Subject: [PATCH 184/204] Make the coin example not quite so literal --- src/ch06-02-match.md | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/ch06-02-match.md b/src/ch06-02-match.md index f75757407b..8009b8a417 100644 --- a/src/ch06-02-match.md +++ b/src/ch06-02-match.md @@ -4,30 +4,31 @@ 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. -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: +Think of a `match` expression 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. In the same way, values +go through each pattern in a `match`, and for the first pattern that the value +"fits", the value will fall into the associated code block to be used during +execution. + +Since we're already talking about coins, let's use them for an example using +`match`! We can write a function 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, + Dime, Quarter, } fn value_in_cents(coin: Coin) -> i32 { match coin { - Coin::Dime => 10, Coin::Penny => 1, Coin::Nickel => 5, + Coin::Dime => 10, Coin::Quarter => 25, } } @@ -66,20 +67,20 @@ but would still return the last value of the block, `1`: ```rust # enum Coin { -# Dime, # Penny, # Nickel, +# Dime, # Quarter, # } # fn value_in_cents(coin: Coin) -> i32 { match coin { - Coin::Dime => 10, Coin::Penny => { println!("Lucky penny!"); 1 }, Coin::Nickel => 5, + Coin::Dime => 10, Coin::Quarter => 25, } } @@ -100,9 +101,9 @@ enum UsState { } enum Coin { - Dime, Penny, Nickel, + Dime, Quarter(UsState), } ``` @@ -125,17 +126,17 @@ in the code for that arm: # } # # enum Coin { -# Dime, # Penny, # Nickel, +# Dime, # Quarter(UsState), # } # fn value_in_cents(coin: Coin) -> i32 { match coin { - Coin::Dime => 10, Coin::Penny => 1, Coin::Nickel => 5, + Coin::Dime => 10, Coin::Quarter(state) => { println!("State quarter from {:?}!", state); 25 From 10fc5d16a9f6e3d051cfbe1af69b2cb09709e3d6 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 21:28:45 -0400 Subject: [PATCH 185/204] Remove lead-in to the patterns section we moved --- src/ch06-02-match.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ch06-02-match.md b/src/ch06-02-match.md index 8009b8a417..b682f1fbb7 100644 --- a/src/ch06-02-match.md +++ b/src/ch06-02-match.md @@ -266,8 +266,3 @@ 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 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. They can also get complex, so let's -take a whole section to cover all of the things that they can do. From a83b968c376a4185ddd2651407bad1d36e8be855 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 21:42:48 -0400 Subject: [PATCH 186/204] Fix heading level so that I can just cat chapters together --- src/ch01-01-installation.md | 12 ++++++------ src/ch01-02-hello-world.md | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/ch01-01-installation.md b/src/ch01-01-installation.md index c3433391c2..07652030b5 100644 --- a/src/ch01-01-installation.md +++ b/src/ch01-01-installation.md @@ -1,4 +1,4 @@ -# Installation +## Installation The first step to using Rust is to install it. You’ll need an internet connection to run the commands in this chapter, as we’ll be downloading Rust @@ -11,7 +11,7 @@ that follow this convention: `$` for commands run as a regular user, and `#` for commands you should be running as an administrator. Lines that don't start with `$` are typically showing the output of the previous command. -## Installing on Linux or Mac +### Installing on Linux or Mac If you're on Linux or a Mac, all you need to do is open a terminal and type this: @@ -27,13 +27,13 @@ your password. If it all goes well, you’ll see this appear: Rust is installed now. Great! ``` -## Installing on Windows +### Installing on Windows If you're on Windows, please download the appropriate [installer][install-page]. [install-page]: https://www.rust-lang.org/install.html -## Uninstalling +### Uninstalling Uninstalling Rust is as easy as installing it. On Linux or Mac, just run the uninstall script: @@ -45,7 +45,7 @@ $ rustup self uninstall If you used the Windows installer, you can re-run the `.msi` and it will give you an uninstall option. -## Troubleshooting +### Troubleshooting If you've got Rust installed, you can open up a shell, and type this: @@ -78,7 +78,7 @@ include [the user’s forum][users] and [Stack Overflow][stackoverflow]. [users]: https://users.rust-lang.org/ [stackoverflow]: http://stackoverflow.com/questions/tagged/rust -## Local documentation +### Local documentation The installer also includes a copy of the documentation locally, so you can read it offline. On Linux or Mac, run `rustup doc` to open the local diff --git a/src/ch01-02-hello-world.md b/src/ch01-02-hello-world.md index d397ae6104..f7d1bf4399 100644 --- a/src/ch01-02-hello-world.md +++ b/src/ch01-02-hello-world.md @@ -1,4 +1,4 @@ -# Hello, World! +## Hello, World! Now that you have Rust installed, let’s write your first Rust program. It's traditional when learning a new language to write a little program to print the @@ -9,7 +9,7 @@ tradition. > makes no specific demands about your editing, tooling, or where your code > lives, so if you prefer an IDE to the command line, that's an option. -## Creating a Project File +### Creating a Project File First, make a file to put your Rust code in. Rust doesn't care where your code lives, but for this book, we'd suggest making a *projects* directory in your @@ -27,7 +27,7 @@ $ cd hello_world > your home directory may not work. > Consult the documentation for your shell for more details. -## Writing and Running a Rust Program +### Writing and Running a Rust Program Next, make a new source file and call it *main.rs*. Rust files always end with the *.rs* extension. If you’re using more than one word in your filename, use @@ -56,7 +56,7 @@ system, you should see the string `Hello, world!` print to the terminal. If you did, then congratulations! You've officially written a Rust program. That makes you a Rust programmer! Welcome. -## Anatomy of a Rust Program +### Anatomy of a Rust Program Now, let’s go over what just happened in your "Hello, world!" program in detail. Here's the first piece of the puzzle: @@ -104,7 +104,7 @@ The line ends with a semicolon (`;`). The `;` indicates that this expression is over, and the next one is ready to begin. Most lines of Rust code end with a `;`. -## Compiling and Running Are Separate Steps +### Compiling and Running Are Separate Steps In "Writing and Running a Rust Program", we showed you how to run a newly created program. We'll break that process down and examine each step now. @@ -160,7 +160,7 @@ and make it easy to share your code with other people and projects. Next, we'll introduce you to a tool called Cargo, which will help you write real-world Rust programs. -# Hello, Cargo! +## Hello, Cargo! Cargo is Rust’s build system and package manager, and Rustaceans use Cargo to manage their Rust projects because it makes a lot of tasks easier. For example, @@ -188,7 +188,7 @@ If you see a version number, great! If you see an error like `command not found`, then you should look at the documentation for the way you installed Rust to determine how to install Cargo separately. -## Creating a Project with Cargo +### Creating a Project with Cargo Let's create a new project using Cargo and look at how it differs from our project in `hello_world`. Go back to your projects directory (or wherever you @@ -277,7 +277,7 @@ the `hello_world` directory, you can convert it to a project that does use Cargo by moving your code into the `src` directory and creating an appropriate `Cargo.toml`. -## Building and Running a Cargo Project +### Building and Running a Cargo Project Now let's look at what's different about building and running your Hello World program through Cargo! To do so, enter the following commands: @@ -337,7 +337,7 @@ So a few more differences we've now seen: 3. Instead of using `rustc`, build a project using `cargo build` (or build and run it in one step with `cargo run`) 4. Instead of the result of the build being put in the same directory as our code, Cargo will put it in the `target/debug` directory. -## Building for Release +### Building for Release When your project is finally ready for release, you can use `cargo build --release` to compile your project with optimizations. This will create an @@ -350,7 +350,7 @@ that we want to run as fast as possible. If you're benchmarking the running time of your code, be sure to run `cargo build --release` and benchmark with the executable in `target/release`. -## Cargo as Convention +### Cargo as Convention With simple projects, Cargo doesn't provide a whole lot of value over just using `rustc`, but it will prove its worth as you continue. With complex From b5602c746fa9114a39dfd7397feb9d2f62ba03e7 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 21:50:46 -0400 Subject: [PATCH 187/204] Add a few more section headers to the tutorial --- src/ch02-00-guessing-game-tutorial.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ch02-00-guessing-game-tutorial.md b/src/ch02-00-guessing-game-tutorial.md index e4471dd3ad..0ad4e27e10 100644 --- a/src/ch02-00-guessing-game-tutorial.md +++ b/src/ch02-00-guessing-game-tutorial.md @@ -111,6 +111,8 @@ println!("Please input your guess."); We previously learned in Chapter 1 that `println!()` is a macro that prints a string to the screen. +### Variable Bindings + ```rust,ignore let mut guess = String::new(); ``` @@ -223,7 +225,11 @@ io::stdin().read_line(&mut guess).expect("failed to read line"); ``` But that gets hard to read. So we’ve split it up, two lines for two method -calls. We already talked about `read_line()`, but what about `expect()`? Well, +calls. + +### The `Result` Type + +We already talked about `read_line()`, but what about `expect()`? Well, we already mentioned that `read_line()` puts what the user types into the `&mut String` we pass it. But it also returns a value: in this case, an [`io::Result`][ioresult]. Rust has a number of types named `Result` in its @@ -259,6 +265,8 @@ actually write error handling. Luckily, if we want to crash if there’s a problem, we can use `expect()`. If we can recover from the error somehow, we’d do something else, but we’ll save that for a future project. +### `println!()` Placeholders + There’s only one line of this first example left, aside from the closing curly brace: From 347e559b7f26d5473ebf9cbe65ad8af549d43eb0 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 21:52:14 -0400 Subject: [PATCH 188/204] Use the author's "we" :) --- src/ch02-00-guessing-game-tutorial.md | 8 ++++---- src/ch03-05-control-flow.md | 2 +- src/ch04-02-references-and-borrowing.md | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ch02-00-guessing-game-tutorial.md b/src/ch02-00-guessing-game-tutorial.md index 0ad4e27e10..0deffef99e 100644 --- a/src/ch02-00-guessing-game-tutorial.md +++ b/src/ch02-00-guessing-game-tutorial.md @@ -584,7 +584,7 @@ match guess.cmp(&secret_number) { If it’s `Less`, we print `Too small!`, if it’s `Greater`, `Too big!`, and if `Equal`, `You win!`. `match` is really useful and is used often in Rust. -I did mention that this won’t quite compile yet, though. Let’s try it: +We did mention that this won’t quite compile yet, though. Let’s try it: ```bash $ cargo build @@ -655,7 +655,7 @@ let guess: u32 = guess.trim().parse() .expect("Please type a number!"); ``` -Wait a minute, I thought we already had a `guess`? We do, but Rust allows us +Wait a minute, didn't we already have a `guess`? We do, but Rust allows us to ‘shadow’ the previous `guess` with a new one. This is often used in this exact situation, where `guess` starts as a `String`, but we want to convert it to a `u32`. Shadowing lets us re-use the `guess` name rather than forcing us @@ -704,8 +704,8 @@ You guessed: 76 Too big! ``` -Nice! You can see I even added spaces before my guess, and it still figured -out that I guessed 76. Run the program a few times. Verify that guessing +Nice! You can see we even added spaces before our guess, and it still figured +out that we guessed 76. Run the program a few times. Verify that guessing the secret number works, as well as guessing a number too small. Now we’ve got most of the game working, but we can only make one guess. Let’s diff --git a/src/ch03-05-control-flow.md b/src/ch03-05-control-flow.md index c646e5207b..500050ca1c 100644 --- a/src/ch03-05-control-flow.md +++ b/src/ch03-05-control-flow.md @@ -274,7 +274,7 @@ again! ^Cagain! ``` -That `^C` there is where I hit `control-c`. You may or may not see "again!" +That `^C` there is where we hit `control-c`. You may or may not see "again!" printed after the `^C`, depending on where the code was in the loop when it received the signal to halt. diff --git a/src/ch04-02-references-and-borrowing.md b/src/ch04-02-references-and-borrowing.md index baff5bf009..bd3c8fe0d8 100644 --- a/src/ch04-02-references-and-borrowing.md +++ b/src/ch04-02-references-and-borrowing.md @@ -86,8 +86,8 @@ This lets us write functions which take references as arguments instead of the values themselves, so that we won’t need to return them to give back ownership. There’s another word for what references do, and that’s ‘borrowing’. Just like -with real life, if I own something, you can borrow it from me. When you’re done, -you have to give it back. +with real life, if a person owns something, you can borrow it from them. When +you’re done, you have to give it back. Speaking of which, what if you try to modify something you borrow from me? Try this code out. Spoiler alert: it doesn’t work! From 6964610a5ca4064c7aa6e1062186bcd1daf78ff2 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 21:53:07 -0400 Subject: [PATCH 189/204] We don't actually end up talking about lifetimes in here --- src/ch04-00-understanding-ownership.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch04-00-understanding-ownership.md b/src/ch04-00-understanding-ownership.md index 9989d95439..ed110878f2 100644 --- a/src/ch04-00-understanding-ownership.md +++ b/src/ch04-00-understanding-ownership.md @@ -3,4 +3,4 @@ Ownership is important to understand: it's Rust's most unique feature, and enables Rust to make memory safety guarantees without needing a garbage collector. We’ll also talk about several related features: borrowing, slices, -and lifetimes, as well as how Rust lays things out in memory. +and how Rust lays things out in memory. From 92085ebd8f9664f31cd8f1e4e73c149e4d4aa6c8 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 21:58:34 -0400 Subject: [PATCH 190/204] Bumping in more section headers --- src/ch04-01-ownership.md | 18 +++++++++--------- src/ch04-02-references-and-borrowing.md | 10 +++++----- src/ch04-03-slices.md | 8 ++++---- src/ch05-01-method-syntax.md | 10 +++++----- src/ch06-01-option.md | 4 ++-- src/ch06-02-match.md | 6 +++--- src/ch06-03-if-let.md | 2 +- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/ch04-01-ownership.md b/src/ch04-01-ownership.md index f99d4e6399..2cd1f0eb05 100644 --- a/src/ch04-01-ownership.md +++ b/src/ch04-01-ownership.md @@ -1,4 +1,4 @@ -# Ownership +## Ownership Rust’s central feature is called ‘ownership’. It is a feature that is straightforward to explain, but has deep implications for the rest of the @@ -20,7 +20,7 @@ Once you understand ownership, you have a good foundation for understanding the features that make Rust unique. In this chapter, we'll learn ownership by going through some examples, focusing on a very common data structure: strings. -## Variable binding scope +### Variable binding scope We've walked through an example of a Rust program already in the tutorial chapter. Now that we’re past basic syntax, we won’t include all of the `fn @@ -54,7 +54,7 @@ In other words, there are two important points in time here: At this point, things are similar to other programming languages. Now let’s build on top of this understanding by introducing the `String` type. -## Strings +### Strings String literals are convenient, but they aren’t the only way that you use strings. For one thing, they’re immutable. For another, not every string is @@ -82,7 +82,7 @@ s.push_str(", world!"); // push_str() appends a literal to a String println!("{}", s); // This will print `hello, world!` ``` -## Memory and allocation +### Memory and allocation So, what’s the difference here? Why can `String` be mutated, but literals cannot? The difference comes down to how these two types deal with memory. @@ -144,7 +144,7 @@ This pattern has a profound impact on the way that Rust code is written. It may seem obvious right now, but things can get tricky in more advanced situations. Let’s go over the first one of those right now. -## Move +### Move What would you expect this code to do? @@ -245,7 +245,7 @@ into `s2`. So what actually happens looks like this: That solves our problem! With only `s2` valid, when it goes out of scope, it alone will free the memory, and we’re done. -## Ownership Rules +### Ownership Rules This leads us to the Ownership Rules: @@ -257,7 +257,7 @@ Furthermore, there’s a design choice that’s implied by this: Rust will never automatically create ‘deep’ copies of your data. Therefore, any _automatic_ copying can be assumed to be inexpensive. -## Clone +### Clone But what if we _do_ want to deeply copy the `String`’s data and not just the `String` itself? There’s a common method for that: `clone()`. We will discuss @@ -284,7 +284,7 @@ When you see a call to `clone()`, you know that some arbitrary code is being executed, and that code may be expensive. It’s a visual indicator that something different is going on here. -## Copy +### Copy There’s one last wrinkle that we haven’t talked about yet. This code works: @@ -322,7 +322,7 @@ but nothing that requires allocation or is some form of resource is `Copy`. Here * Tuples, but only if they contain types which are also `Copy`. `(i32, i32)` is `Copy`, but `(i32, String)` is not. -## Ownership and functions +### Ownership and functions Passing a value to a function has similar semantics as assigning it: diff --git a/src/ch04-02-references-and-borrowing.md b/src/ch04-02-references-and-borrowing.md index bd3c8fe0d8..6c0f3d8282 100644 --- a/src/ch04-02-references-and-borrowing.md +++ b/src/ch04-02-references-and-borrowing.md @@ -1,4 +1,4 @@ -# References and Borrowing +## References and Borrowing At the end of the last section, we had some example Rust that wasn’t very good. Here it is again: @@ -117,7 +117,7 @@ error: cannot borrow immutable borrowed content `*some_string` as mutable Just like bindings are immutable by default, so are references. We’re not allowed to modify something we have a reference to. -## Mutable references +### Mutable references We can fix this bug! Just a small tweak: @@ -209,7 +209,7 @@ Whew! We _also_ cannot have a mutable reference while we have an immutable one. Users of an immutable reference don’t expect the values to suddenly change out from under them! Multiple immutable references are okay, however. -## Dangling references +### Dangling references In languages with pointers, it’s easy to create a “dangling pointer” by freeing some memory while keeping around a pointer to that memory. In Rust, by @@ -240,7 +240,7 @@ error[E0106]: missing lifetime specifier 5 | fn dangle() -> &String { | ^^^^^^^ | - = help: this function's return type contains a borrowed value, but there is no + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from = help: consider giving it a 'static lifetime @@ -285,7 +285,7 @@ fn no_dangle() -> String { This works, no problem. Ownership is moved out, nothing is deallocated. -## The Rules of References +### The Rules of References Here’s a recap of what we’ve talked about: diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index f098485deb..10228a9831 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -1,4 +1,4 @@ -# Slices +## Slices So far, we’ve talked about types that have ownership, like `String`, and ones that don’t, like `&String`. There is another kind of type which does not have @@ -114,7 +114,7 @@ around which need to be kept in sync. Luckily, Rust has a solution to this problem: string slices. -# String slices +## String slices A string slice looks like this: @@ -253,7 +253,7 @@ The type of `s` here is `&str`: It’s a slice, pointing to that specific point of the binary. This is also why string literals are immutable; `&str` is an immutable reference. -## String slices as arguments +### String slices as arguments Knowing that you can take slices of both literals and `String`s leads us to one more improvement on `first_word()`, and that’s its signature: @@ -303,7 +303,7 @@ fn main() { } ``` -# Other slices +## Other slices String slices, as you might imagine, are specific to strings. But there’s a more general slice type, too. Consider arrays: diff --git a/src/ch05-01-method-syntax.md b/src/ch05-01-method-syntax.md index aeef89529b..925f70f3ab 100644 --- a/src/ch05-01-method-syntax.md +++ b/src/ch05-01-method-syntax.md @@ -1,4 +1,4 @@ -# Method Syntax +## Method Syntax In the last section on ownership, we made several references to ‘methods’. Methods look like this: @@ -34,7 +34,7 @@ The nested-functions version reads in reverse: the program executes `f()`, then Before we get into the details, let’s talk about how to define your own methods. -## Defining methods +### Defining methods We can define methods with the `impl` keyword. `impl` is short for ‘implementation’. Doing so looks like this: @@ -123,7 +123,7 @@ rarely used. An example of a time to do that would be if we wanted to have a method that would transform `self` into something else and prevent other code from using the value of `self` after the transformation happens. -### Methods and automatic referencing +#### Methods and automatic referencing We’ve left out an important detail. It’s in this line of the example: @@ -145,12 +145,12 @@ or `&mut`s to match the signature. In other words, these are the same: # x: f64, # y: f64, # } -# +# # impl Point { # fn distance(&self, other: &Point) -> f64 { # let x_squared = f64::powi(other.x - self.x, 2); # let y_squared = f64::powi(other.y - self.y, 2); -# +# # f64::sqrt(x_squared + y_squared) # } # } diff --git a/src/ch06-01-option.md b/src/ch06-01-option.md index be8444cf1d..9e84b0d167 100644 --- a/src/ch06-01-option.md +++ b/src/ch06-01-option.md @@ -1,4 +1,4 @@ -# Option +## Option 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. @@ -18,7 +18,7 @@ The inventor of this concept has this to say: > implement. This has led to innumerable errors, vulnerabilities, and system > crashes, which have probably caused a billion dollars of pain and damage in > the last forty years. -> +> > - Tony Hoare "Null References: The Billion Dollar Mistake" The problem with null values is twofold: first, a value can be null or not, at diff --git a/src/ch06-02-match.md b/src/ch06-02-match.md index b682f1fbb7..6e7787fb45 100644 --- a/src/ch06-02-match.md +++ b/src/ch06-02-match.md @@ -1,4 +1,4 @@ -# Match +## 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 @@ -212,7 +212,7 @@ 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. -## Matches are exhaustive +### Matches are exhaustive There's one other aspect of `match` we didn't talk about. Consider this version of `plus_one()`: @@ -243,7 +243,7 @@ every last option possible in order to be valid. Especially in the case of have null and thus making the billion-dollar mistake we discussed in the previous section. -## The _ placeholder +### The _ placeholder 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 diff --git a/src/ch06-03-if-let.md b/src/ch06-03-if-let.md index a9748e7841..ee19884db1 100644 --- a/src/ch06-03-if-let.md +++ b/src/ch06-03-if-let.md @@ -1,4 +1,4 @@ -# if let +## if let There's one more advanced control flow structure we haven't discussed: `if let`. Imagine we're in a situation like this: From bdc30d409089eb1d09f9b97fe7eb569cb15f90b6 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 22:07:25 -0400 Subject: [PATCH 191/204] First third to nostarch! --- nostarch/chapter01.md | 492 +++++ nostarch/chapter02.md | 966 ++++++++++ nostarch/chapter03.md | 1303 +++++++++++++ nostarch/{chapter4.md => chapter04.md} | 638 +++---- nostarch/chapter05.md | 486 +++++ nostarch/chapter06.md | 601 ++++++ nostarch/chapter3.md | 2332 ------------------------ nostarch/chapter5.md | 697 ------- nostarch/chapter6.md | 738 -------- 9 files changed, 4181 insertions(+), 4072 deletions(-) create mode 100644 nostarch/chapter01.md create mode 100644 nostarch/chapter02.md create mode 100644 nostarch/chapter03.md rename nostarch/{chapter4.md => chapter04.md} (54%) create mode 100644 nostarch/chapter05.md create mode 100644 nostarch/chapter06.md delete mode 100644 nostarch/chapter3.md delete mode 100644 nostarch/chapter5.md delete mode 100644 nostarch/chapter6.md diff --git a/nostarch/chapter01.md b/nostarch/chapter01.md new file mode 100644 index 0000000000..2cbf8700da --- /dev/null +++ b/nostarch/chapter01.md @@ -0,0 +1,492 @@ +# Introduction + +Welcome to “The Rust Programming Language”, an introductory book about Rust. +Rust is a programming language that’s focused on safety, speed, and +concurrency. Its design lets you create programs that have the performance and +control of a low-level language, but with helpful abstractions that feel like a +high-level language. The Rust community welcomes all programmers who have their +experience in languages like C and are looking for a safer alternative, as well +as programmers from languages like Python who are looking for ways to write more +performant code without losing expressiveness. + +Rust provides the majority of its safety checks at compile time and without a +garbage collector so that your program's runtime isn't impacted. This makes it +useful in a number of use cases that other languages aren’t good at: embedding +in other languages, programs with specific space and time requirements, and +writing low-level code, like device drivers and operating systems. It's also +great for web applications: it powers the Rust package registry site, crates.io! +We're excited to see what _you_ create with Rust. + +This book is written for a reader who already knows how to program in at least +one programming language. After reading this book, you should be comfortable +writing Rust programs. We’ll be learning Rust through small, focused examples +that build on each other to demonstrate how to use various features of Rust as +well as how they work behind the scenes. + +## Contributing to the book + +This book is open source. If you find an error, please don’t hesitate to file an +issue or send a pull request [on GitHub]. + +[on GitHub]: https://github.com/rust-lang/book + +## Installation + +The first step to using Rust is to install it. You’ll need an internet +connection to run the commands in this chapter, as we’ll be downloading Rust +from the internet. + +We’ll be showing off a number of commands using a terminal, and those lines all +start with `$`. You don't need to type in the `$`s; they are there to indicate +the start of each command. You’ll see many tutorials and examples around the web +that follow this convention: `$` for commands run as a regular user, and `#` +for commands you should be running as an administrator. Lines that don't start +with `$` are typically showing the output of the previous command. + +### Installing on Linux or Mac + +If you're on Linux or a Mac, all you need to do is open a terminal and type +this: + +```bash +$ curl https://sh.rustup.rs -sSf | sh +``` + +This will download a script and start the installation. You may be prompted for +your password. If it all goes well, you’ll see this appear: + +```bash +Rust is installed now. Great! +``` + +### Installing on Windows + +If you're on Windows, please download the appropriate [installer][install-page]. + +[install-page]: https://www.rust-lang.org/install.html + +### Uninstalling + +Uninstalling Rust is as easy as installing it. On Linux or Mac, just run +the uninstall script: + +```bash +$ rustup self uninstall +``` + +If you used the Windows installer, you can re-run the `.msi` and it will give +you an uninstall option. + +### Troubleshooting + +If you've got Rust installed, you can open up a shell, and type this: + +```bash +$ rustc --version +``` + +You should see the version number, commit hash, and commit date in a format +similar to this for the latest stable version at the time you install: + +```bash +rustc x.y.z (abcabcabc yyyy-mm-dd) +``` + +If you see this, Rust has been installed successfully! +Congrats! + +If you don't and you're on Windows, check that Rust is in your `%PATH%` system +variable. If it isn't, run the installer again, select "Change" on the "Change, +repair, or remove installation" page and ensure "Add to PATH" is checked. + +If not, there are a number of places where you can get help. The easiest is +[the #rust IRC channel on irc.mozilla.org][irc], which you can access through +[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans +(a silly nickname we call ourselves) who can help you out. Other great resources +include [the user’s forum][users] and [Stack Overflow][stackoverflow]. + +[irc]: irc://irc.mozilla.org/#rust +[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust +[users]: https://users.rust-lang.org/ +[stackoverflow]: http://stackoverflow.com/questions/tagged/rust + +### Local documentation + +The installer also includes a copy of the documentation locally, so you can +read it offline. On Linux or Mac, run `rustup doc` to open the local +documentation in your browser. On Windows, the documentation is in a +`share/doc` directory inside the directory where Rust was installed. + +## Hello, World! + +Now that you have Rust installed, let’s write your first Rust program. It's +traditional when learning a new language to write a little program to print the +text “Hello, world!” to the screen, and in this section, we'll follow that +tradition. + +> Note: This book assumes basic familiarity with the command line. Rust itself +> makes no specific demands about your editing, tooling, or where your code +> lives, so if you prefer an IDE to the command line, that's an option. + +### Creating a Project File + +First, make a file to put your Rust code in. Rust doesn't care where your code +lives, but for this book, we'd suggest making a *projects* directory in your +home directory and keeping all your projects there. Open a terminal and enter +the following commands to make a directory for this particular project: + +```bash +$ mkdir ~/projects +$ cd ~/projects +$ mkdir hello_world +$ cd hello_world +``` + +> Note: If you’re on Windows and not using PowerShell, the `~` that represents +> your home directory may not work. +> Consult the documentation for your shell for more details. + +### Writing and Running a Rust Program + +Next, make a new source file and call it *main.rs*. Rust files always end with +the *.rs* extension. If you’re using more than one word in your filename, use +an underscore to separate them. For example, you'd use *hello_world.rs* rather +than *helloworld.rs*. + +Now open the *main.rs* file you just created, and type the following code: + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +Save the file, and go back to your terminal window. On Linux or OSX, enter the +following commands: + +```bash +$ rustc main.rs +$ ./main +Hello, world! +``` + +On Windows, just replace `main` with `main.exe`. Regardless of your operating +system, you should see the string `Hello, world!` print to the terminal. If you +did, then congratulations! You've officially written a Rust program. That makes +you a Rust programmer! Welcome. + +### Anatomy of a Rust Program + +Now, let’s go over what just happened in your "Hello, world!" program in +detail. Here's the first piece of the puzzle: + +```rust +fn main() { + +} +``` + +These lines define a *function* in Rust. The `main` function is special: it's +the first thing that is run for every executable Rust program. The first line +says, “I’m declaring a function named `main` that takes no arguments and +returns nothing.” If there were arguments, they would go inside the parentheses +(`(` and `)`). We aren’t returning anything from this function, so we have +omitted the return type entirely. If there was a return type, there would be a +`->` and the return type after the parentheses. + +Also note that the function body is wrapped in curly braces (`{` and `}`). Rust +requires these around all function bodies. It's considered good style to put +the opening curly brace on the same line as the function declaration, with one +space in between. + +Inside the `main()` function: + +```rust + println!("Hello, world!"); +``` + +This line does all of the work in this little program: it prints text to the +screen. There are a number of details that are important here. The first is +that it’s indented with four spaces, not tabs. + +The second important part is `println!()`. This is calling a Rust *macro*, +which is how metaprogramming is done in Rust. If it were calling a function +instead, it would look like this: `println()` (without the `!`). We'll discuss +Rust macros in more detail in Chapter XX, but for now you just need to know +that when you see a `!` that means that you’re calling a macro instead of a +normal function. + +Next is `"Hello, world!"` which is a *string*. We pass this string as an +argument to `println!()`, which prints the string to the screen. Easy enough! + +The line ends with a semicolon (`;`). The `;` indicates that this expression is +over, and the next one is ready to begin. Most lines of Rust code end with a +`;`. + +### Compiling and Running Are Separate Steps + +In "Writing and Running a Rust Program", we showed you how to run a newly +created program. We'll break that process down and examine each step now. + +Before running a Rust program, you have to compile it. You can use the Rust +compiler by entering the `rustc` command and passing it the name of your source +file, like this: + +```bash +$ rustc main.rs +``` + +If you come from a C or C++ background, you'll notice that this is similar to +`gcc` or `clang`. After compiling successfully, Rust should output a binary +executable, which you can see on Linux or OSX by entering the `ls` command in +your shell as follows: + +```bash +$ ls +main main.rs +``` + +On Windows, you'd enter: + +```bash +$ dir +main.exe main.rs +``` + +This shows we have two files: the source code, with the `.rs` extension, and the +executable (`main.exe` on Windows, `main` everywhere else). All that's left to +do from here is run the `main` or `main.exe` file, like this: + +```bash +$ ./main # or main.exe on Windows +``` + +If *main.rs* were your "Hello, world!" program, this would print `Hello, +world!` to your terminal. + +If you come from a dynamic language like Ruby, Python, or JavaScript, you may +not be used to compiling and running a program being separate steps. Rust is an +*ahead-of-time compiled* language, which means that you can compile a program, +give it to someone else, and they can run it even without having Rust +installed. If you give someone a `.rb`, `.py`, or `.js` file, on the other +hand, they need to have a Ruby, Python, or JavaScript implementation installed +(respectively), but you only need one command to both compile and run your +program. Everything is a tradeoff in language design. + +Just compiling with `rustc` is fine for simple programs, but as your project +grows, you'll want to be able to manage all of the options your project has +and make it easy to share your code with other people and projects. Next, we'll +introduce you to a tool called Cargo, which will help you write real-world Rust +programs. + +## Hello, Cargo! + +Cargo is Rust’s build system and package manager, and Rustaceans use Cargo to +manage their Rust projects because it makes a lot of tasks easier. For example, +Cargo takes care of building your code, downloading the libraries your code +depends on, and building those libraries. We call libraries your code needs +‘dependencies’ since your code depends on them. + +The simplest Rust programs, like the one we've written so far, don’t have any +dependencies, so right now, you'd only be using the part of Cargo that can take +care of building your code. As you write more complex Rust programs, you’ll +want to add dependencies, and if you start off using Cargo, that will be a lot +easier to do. + +As the vast, vast majority of Rust projects use Cargo, we will assume that +you’re using it for the rest of the book. Cargo comes installed with Rust +itself, if you used the official installers as covered in the Installation +chapter. If you installed Rust through some other means, you can check if you +have Cargo installed by typing the following into your terminal: + +```bash +$ cargo --version +``` + +If you see a version number, great! If you see an error like `command not +found`, then you should look at the documentation for the way you installed +Rust to determine how to install Cargo separately. + +### Creating a Project with Cargo + +Let's create a new project using Cargo and look at how it differs from our +project in `hello_world`. Go back to your projects directory (or wherever you +decided to put your code): + +```bash +$ cd ~/projects +``` + +And then run: + +```bash +$ cargo new hello_cargo --bin +$ cd hello_cargo +``` + +We passed the `--bin` argument to `cargo new` because our goal is to make an +executable application, as opposed to a library. Executables are often called +*binaries* (as in `/usr/bin`, if you’re on a Unix system). `hello_cargo` is the +name we've chosen for our project, and Cargo creates its files in a directory +of the same name that we can then go into. + +If we list the files in the `hello_cargo` directory, we can see that Cargo has +generated two files and one directory for us: a `Cargo.toml` and a *src* +directory with a *main.rs* file inside. It has also initialized a new `git` +repository in the `hello_cargo` directory for us; you can change this to use a +different version control system, or no version control system, by using the +`--vcs` flag. + +Open up `Cargo.toml` in your text editor of choice. It should look something +like this: + +```toml +[package] +name = "hello_cargo" +version = "0.1.0" +authors = ["Your Name "] + +[dependencies] +``` + +This file is in the *[TOML]* (Tom's Obvious, Minimal Language) format. TOML is +similar to INI but has some extra goodies and is used as Cargo’s +configuration format. + +[TOML]: https://github.com/toml-lang/toml + +The first line, `[package]`, is a section heading that indicates that the +following statements are configuring a package. As we add more information to +this file, we’ll add other sections. + +The next three lines set the three bits of configuration that Cargo needs to +see in order to know that it should compile your program: its name, what +version it is, and who wrote it. Cargo gets your name and email information +from your environment. If it’s not correct, go ahead and fix that and save the +file. + +The last line, `[dependencies]`, is the start of a section for you to list any +crates that your project will depend on so that Cargo knows to download and +compile those too. We won't need any other crates for this project, but we will +in the guessing game tutorial in the next chapter. + +Now let's look at `src/main.rs`: + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +Cargo has generated a "Hello World!" for you, just like the one we wrote +earlier! So that part is the same. The differences between our previous project +and the project generated by Cargo that we've seen so far are: + +1. Our code goes in the `src` directory +2. The top level contains a `Cargo.toml` configuration file + +Cargo expects your source files to live inside the *src* directory so that the +top-level project directory is just for READMEs, license information, +configuration files, and anything else not related to your code. In this way, +using Cargo helps you keep your projects nice and tidy. There's a place for +everything, and everything is in its place. + +If you started a project that doesn't use Cargo, as we did with our project in +the `hello_world` directory, you can convert it to a project that does use +Cargo by moving your code into the `src` directory and creating an appropriate +`Cargo.toml`. + +### Building and Running a Cargo Project + +Now let's look at what's different about building and running your Hello World +program through Cargo! To do so, enter the following commands: + +```bash +$ cargo build + Compiling hello_cargo v0.1.0 (file:///home/yourname/projects/hello_cargo) +``` + +This should have created an executable file in `target/debug/hello_cargo` (or `target/debug/hello_cargo.exe` on Windows), which you can run with this command: + +```bash +$ ./target/debug/hello_cargo # or ./target/debug/hello_cargo.exe on Windows +Hello, world! +``` + +Bam! If all goes well, `Hello, world!` should print to the terminal once more. + +Running `cargo build` for the first time also causes Cargo to create a new file +at the top level called *Cargo.lock*, which looks like this: + +```toml +[root] +name = "hello_cargo" +version = "0.1.0" +``` + +Cargo uses the *Cargo.lock* file to keep track of dependencies in your +application. This project doesn't have dependencies, so the file is a bit +sparse. Realistically, you won't ever need to touch this file yourself; just +let Cargo handle it. + +We just built a project with `cargo build` and ran it with +`./target/debug/hello_cargo`, but we can actually do both in one step with +`cargo run` as follows: + +```bash +$ cargo run + Running `target/debug/hello_cargo` +Hello, world! +``` + +Notice that this time, we didn't see the output that Cargo was compiling +`hello_cargo`. Cargo figured out that the files haven’t changed, so it just ran +the binary. If you had modified your source code, Cargo would have rebuilt the +project before running it, and you would have seen something like this: + +```bash +$ cargo run + Compiling hello_cargo v0.1.0 (file:///home/yourname/projects/hello_cargo) + Running `target/debug/hello_cargo` +Hello, world! +``` + +So a few more differences we've now seen: + +3. Instead of using `rustc`, build a project using `cargo build` (or build and run it in one step with `cargo run`) +4. Instead of the result of the build being put in the same directory as our code, Cargo will put it in the `target/debug` directory. + +### Building for Release + +When your project is finally ready for release, you can use `cargo build +--release` to compile your project with optimizations. This will create an +executable in `target/release` instead of `target/debug`. These optimizations +make your Rust code run faster, but turning them on makes your program take +longer to compile. This is why there are two different profiles: one for +development when you want to be able to rebuild quickly and often, and one for +building the final program you’ll give to a user that won't be rebuilt and +that we want to run as fast as possible. If you're benchmarking the running +time of your code, be sure to run `cargo build --release` and benchmark with +the executable in `target/release`. + +### Cargo as Convention + +With simple projects, Cargo doesn't provide a whole lot of value over just +using `rustc`, but it will prove its worth as you continue. With complex +projects composed of multiple crates, it’s much easier to let Cargo coordinate +the build. With Cargo, you can just run `cargo build`, and it should work the +right way. Even though this project is simple, it now uses much of the real +tooling you’ll use for the rest of your Rust career. In fact, you can get +started with virtually all Rust projects you might find that you want to work +on with the following commands: + +```bash +$ git clone someurl.com/someproject +$ cd someproject +$ cargo build +``` + +> Note: If you want to look at Cargo in more detail, check out the official +[Cargo guide], which covers all of its features. + +[Cargo guide]: http://doc.crates.io/guide.html diff --git a/nostarch/chapter02.md b/nostarch/chapter02.md new file mode 100644 index 0000000000..0deffef99e --- /dev/null +++ b/nostarch/chapter02.md @@ -0,0 +1,966 @@ +# Guessing Game + +Let's jump into Rust with a hands-on project! We’ll implement a classic +beginner programming problem: the guessing game. Here’s how it works: Our +program will generate a random integer between one and a hundred. It will then +prompt us to enter a guess. Upon entering our guess, it will tell us if we’re +too low or too high. Once we guess correctly, it will congratulate us. + +## Set up + +Let’s set up a new project. Go to your projects directory, and create a new project using Cargo. + +```bash +$ cd ~/projects +$ cargo new guessing_game --bin +$ cd guessing_game +``` + +We pass the name of our project to `cargo new`, then the `--bin` flag, since +we’re going to be making another binary like in Chapter 1. + +Take a look at the generated `Cargo.toml`: + +```toml +[package] +name = "guessing_game" +version = "0.1.0" +authors = ["Your Name "] + +[dependencies] +``` + +If the authors information that Cargo got from your environment is not correct, +go ahead and fix that. + +And as we saw in the last chapter, `cargo new` generates a ‘Hello, world!’ for +us. Check out `src/main.rs`: + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +Let’s try compiling what Cargo gave us and running it in the same step, using the `cargo run` command: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/debug/guessing_game` +Hello, world! +``` + +Great! The `run` command comes in handy when you need to rapidly iterate on a +project. Our game is such a project: we want to quickly test each +iteration before moving on to the next one. + +Now open up your `src/main.rs` again. We’ll be writing all of our code in this +file. + +## Processing a Guess + +Let’s get to it! The first thing we need to do for our guessing game is +allow our player to input a guess. Put this in your `src/main.rs`: + +```rust,ignore +use std::io; + +fn main() { + println!("Guess the number!"); + + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("Failed to read line"); + + println!("You guessed: {}", guess); +} +``` + +There’s a lot here! Let’s go over it, bit by bit. + +```rust,ignore +use std::io; +``` + +We’ll need to take user input and then print the result as output. As such, we +need the `io` library from the standard library. Rust only imports a few things +by default into every program, [the ‘prelude’][prelude]. If it’s not in the +prelude, you’ll have to `use` it directly. Using the `std::io` library gets +you a number of useful `io`-related things, so that's what we've done here. + +[prelude]: ../std/prelude/index.html + +```rust,ignore +fn main() { +``` + +As you’ve seen in Chapter 1, the `main()` function is the entry point into the +program. The `fn` syntax declares a new function, the `()`s indicate that +there are no arguments, and `{` starts the body of the function. + +```rust,ignore +println!("Guess the number!"); + +println!("Please input your guess."); +``` + +We previously learned in Chapter 1 that `println!()` is a macro that +prints a string to the screen. + +### Variable Bindings + +```rust,ignore +let mut guess = String::new(); +``` + +Now we’re getting interesting! There’s a lot going on in this little line. +The first thing to notice is that this is a let statement, which is +used to create what are called ‘variable bindings’. Here's an example: + +```rust,ignore +let foo = bar; +``` + +This will create a new binding named `foo`, and bind it to the value `bar`. In +many languages, this is called a ‘variable’, but Rust’s variable bindings have +a few tricks up their sleeves. + +For example, they’re immutable by default. That’s why our example +uses `mut`: it makes a binding mutable, rather than immutable. + +```rust +let foo = 5; // immutable. +let mut bar = 5; // mutable +``` + +Oh, and `//` will start a comment, until the end of the line. Rust ignores +everything in comments. + +So now we know that `let mut guess` will introduce a mutable binding named +`guess`, but we have to look at the other side of the `=` for what it’s +bound to: `String::new()`. + +`String` is a string type, provided by the standard library. A +[`String`][string] is a growable, UTF-8 encoded bit of text. + +[string]: ../std/string/struct.String.html + +The `::new()` syntax uses `::` because this is an ‘associated function’ of +a particular type. That is to say, it’s associated with `String` itself, +rather than a particular instance of a `String`. Some languages call this a +‘static method’. + +This function is named `new()`, because it creates a new, empty `String`. +You’ll find a `new()` function on many types, as it’s a common name for making +a new value of some kind. + +Let’s move forward: + +```rust,ignore +io::stdin().read_line(&mut guess) + .expect("Failed to read line"); +``` + +Let’s go through this together bit-by-bit. The first line has two parts. Here’s +the first: + +```rust,ignore +io::stdin() +``` + +Remember how we `use`d `std::io` on the first line of the program? We’re now +calling an associated function on it. If we didn’t `use std::io`, we could +have written this line as `std::io::stdin()`. + +This particular function returns a handle to the standard input for your +terminal. More specifically, a [std::io::Stdin][iostdin]. + +[iostdin]: ../std/io/struct.Stdin.html + +The next part will use this handle to get input from the user: + +```rust,ignore +.read_line(&mut guess) +``` + +Here, we call the [`read_line()`][read_line] method on our handle. We’re also +passing one argument to `read_line()`: `&mut guess`. + +[read_line]: ../std/io/struct.Stdin.html#method.read_line + +Remember how we bound `guess` above? We said it was mutable. However, +`read_line` doesn’t take a `String` as an argument: it takes a `&mut String`. +The `&` is the feature of Rust called a ‘reference’, which allows you to have +multiple ways to access one piece of data in order to reduce copying. +References are a complex feature, as one of Rust’s major selling points is how +safe and easy it is to use references. We don’t need to know a lot of those +details to finish our program right now, though; Chapter XX will cover them in +more detail. For now, all we need to know is that like `let` bindings, +references are immutable by default. Hence, we need to write `&mut guess`, +rather than `&guess`. + +Why does `read_line()` take a mutable reference to a string? Its job is +to take what the user types into standard input and place that into a +string. So it takes that string as an argument, and in order to add +the input, that string needs to be mutable. + +But we’re not quite done with this line of code, though. While it’s +a single line of text, it’s only the first part of the single logical line of +code. This is the second part of the line: + +```rust,ignore +.expect("Failed to read line"); +``` + +When you call a method with the `.foo()` syntax, you may introduce a newline +and other whitespace. This helps you split up long lines. We _could_ have +written this code as: + +```rust,ignore +io::stdin().read_line(&mut guess).expect("failed to read line"); +``` + +But that gets hard to read. So we’ve split it up, two lines for two method +calls. + +### The `Result` Type + +We already talked about `read_line()`, but what about `expect()`? Well, +we already mentioned that `read_line()` puts what the user types into the `&mut +String` we pass it. But it also returns a value: in this case, an +[`io::Result`][ioresult]. Rust has a number of types named `Result` in its +standard library: a generic [`Result`][result], and then specific versions for +sub-libraries, like `io::Result`. + +[ioresult]: ../std/io/type.Result.html +[result]: ../std/result/enum.Result.html + +The purpose of these `Result` types is to encode error handling information. +Values of the `Result` type, like any type, have methods defined on them. In +this case, `io::Result` has an [`expect()` method][expect] that takes a value +it’s called on, and if it isn’t a successful result, will cause our program to +crash and display the message that we passed as an argument to `expect()`. + +[expect]: ../std/result/enum.Result.html#method.expect + +If we don't call this method, our program will compile, but we’ll get a warning: + +```bash +$ cargo build + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) +src/main.rs:10:5: 10:39 warning: unused result which must be used, +#[warn(unused_must_use)] on by default +src/main.rs:10 io::stdin().read_line(&mut guess); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +Rust warns us that we haven’t used the `Result` value. This warning comes from +a special annotation that `io::Result` has. Rust is trying to tell you that you +haven’t handled a possible error. The right way to suppress the error is to +actually write error handling. Luckily, if we want to crash if there’s a +problem, we can use `expect()`. If we can recover from the error somehow, we’d +do something else, but we’ll save that for a future project. + +### `println!()` Placeholders + +There’s only one line of this first example left, aside from the closing curly +brace: + +```rust,ignore + println!("You guessed: {}", guess); +} +``` + +This prints out the string we saved our input in. The `{}`s are a placeholder: +think of `{}` as little crab pincers, holding a value in place. The first `{}` +holds the first value after the format string, the second set holds the second +value, and so on. Printing out multiple values in one call to `println!()` would then look like this: + +```rust +let x = 5; +let y = 10; + +println!("x and y: {} and {}", x, y); +``` + +Which would print out "x and y: 5 and 10". + +Anyway, back to our guessing game. We can run what we have with `cargo run`: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/debug/guessing_game` +Guess the number! +Please input your guess. +6 +You guessed: 6 +``` + +All right! Our first part is done: we can get input from the keyboard and then +print it back out. + +## Generating a secret number + +Next, we need to generate a secret number. Rust does not yet include random +number functionality in its standard library. The Rust team does, however, +provide a [`rand` crate][randcrate]. A ‘crate’ is a package of Rust code. +We’ve been building a ‘binary crate’, which is an executable. `rand` is a +‘library crate’, which contains code that’s intended to be used with other +programs. + +[randcrate]: https://crates.io/crates/rand + +Using external crates is where Cargo really shines. Before we can write +the code using `rand`, we need to modify our `Cargo.toml`. Open it up, and +add this line at the bottom beneath the `[dependencies]` section header that +Cargo created for you: + +```toml +[dependencies] + +rand = "0.3.14" +``` + +The `[dependencies]` section of `Cargo.toml` is like the `[package]` section: +everything that follows the section heading is part of that section, until +another section starts. Cargo uses the dependencies section to know what +dependencies on external crates you have and what versions of those crates you +require. In this case, we’ve specified the `rand` crate with the semantic +version specifier `0.3.14`. Cargo understands [Semantic Versioning][semver], a +standard for writing version numbers. A bare number like above is actually +shorthand for `^0.3.14`, which means "any version that has a public API +compatible with version 0.3.14". + +[semver]: http://semver.org + +Now, without changing any of our code, let’s build our project: + +```bash +$ cargo build + Updating registry `https://github.com/rust-lang/crates.io-index` + Downloading rand v0.3.14 + Downloading libc v0.2.14 + Compiling libc v0.2.14 + Compiling rand v0.3.14 + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) +``` + +You may see different versions (but they will be compatible, thanks to semver!) +and the lines may be in a different order. + +Lots of new output! Now that we have an external dependency, Cargo fetches the +latest versions of everything from the *registry*, which is a copy of data from +[Crates.io][cratesio]. Crates.io is where people in the Rust ecosystem +post their open source Rust projects for others to use. + +[cratesio]: https://crates.io + +After updating the registry, Cargo checks our `[dependencies]` and downloads +any we don’t have yet. In this case, while we only said we wanted to depend on +`rand`, we’ve also grabbed a copy of `libc`. This is because `rand` depends on +`libc` to work. After downloading them, it compiles them and then compiles +our project. + +If we run `cargo build` again, we’ll get different output: + +```bash +$ cargo build +``` + +That’s right, no output! Cargo knows that our project has been built, that +all of its dependencies are built, and that no changes have been made. There’s +no reason to do all that stuff again. With nothing to do, it simply +exits. If we open up `src/main.rs`, make a trivial change, then save it again, +we’ll only see one line: + +```bash +$ cargo build + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) +``` + +What happens when next week version `v0.3.15` of the `rand` crate comes out, +with an important bugfix? While getting bugfixes is important, what if `0.3.15` +contains a regression that breaks our code? + +The answer to this problem is the `Cargo.lock` file created the first time we +ran `cargo build` that is now in your project directory. When you build your +project for the first time, Cargo figures out all of the versions that fit your +criteria then writes them to the `Cargo.lock` file. When you build your project +in the future, Cargo will see that the `Cargo.lock` file exists and then use +that specific version rather than do all the work of figuring out versions +again. This lets you have a repeatable build automatically. In other words, +we’ll stay at `0.3.14` until we explicitly upgrade, and so will anyone who we +share our code with, thanks to the lock file. + +What about when we _do_ want to use `v0.3.15`? Cargo has another command, +`update`, which says ‘ignore the `Cargo.lock` file and figure out all the +latest versions that fit what we’ve specified in `Cargo.toml`. If that works, +write those versions out to the lock file’. But by default, Cargo will only +look for versions larger than `0.3.0` and smaller than `0.4.0`. If we want to +move to `0.4.x`, we’d have to update what is in the `Cargo.toml` file. When we +do, the next time we `cargo build`, Cargo will update the index and re-evaluate +our `rand` requirements. + +There’s a lot more to say about [Cargo][doccargo] and [its +ecosystem][doccratesio] that we will get into in Chapter XX, but for now, +that’s all we need to know. Cargo makes it really easy to re-use libraries, so +Rustaceans are able to write smaller projects which are assembled out of a +number of sub-packages. + +[doccargo]: http://doc.crates.io +[doccratesio]: http://doc.crates.io/crates-io.html + +Let’s get on to actually _using_ `rand`. Here’s our next step: + +```rust,ignore +extern crate rand; + +use std::io; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + println!("You guessed: {}", guess); +} +``` + +The first thing we’ve done is change the first line. It now says `extern crate +rand`. Because we declared `rand` in our `[dependencies]`, we can now put +`extern crate` in our code to let Rust know we’ll be making use of that +dependency. This also does the equivalent of a `use rand;` as well, so we can +call anything in the `rand` crate by prefixing it with `rand::`. + +Next, we added another `use` line: `use rand::Rng`. We’re going to use a +method in a moment, and it requires that `Rng` be in scope to work. The basic +idea is this: methods are defined on something called ‘traits’, and for the +method to work, it needs the trait to be in scope. For more about the +details, read the traits section in Chapter XX. + +There are two other lines we added, in the middle: + +```rust,ignore +let secret_number = rand::thread_rng().gen_range(1, 101); + +println!("The secret number is: {}", secret_number); +``` + +We use the `rand::thread_rng()` function to get a copy of the random number +generator, which is local to the particular thread of execution +we’re in. Because we put `use rand::Rng` above, the random number generator has +a `gen_range()` method available. This method takes two numbers as arguments +and generates a random number between them. It’s inclusive on the lower bound +but exclusive on the upper bound, so we need `1` and `101` to ask for a number +ranging from one to a hundred. + +The second line prints out the secret number. This is useful while +we’re developing our program to let us easily test it out, but we’ll be +deleting it for the final version. It’s not much of a game if it prints out +the answer when you start it up! + +Try running our new program a few times: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/debug/guessing_game` +Guess the number! +The secret number is: 7 +Please input your guess. +4 +You guessed: 4 +$ cargo run + Running `target/debug/guessing_game` +Guess the number! +The secret number is: 83 +Please input your guess. +5 +You guessed: 5 +``` + +You should get different random numbers, and they should all be between 1 and +100. Great job! Next up: comparing our guess to the secret number. + +## Comparing guesses + +Now that we’ve got user input, let’s compare our guess to the secret number. +Here’s part of our next step. It won't quite compile yet though: + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), + } +} +``` + +A few new bits here. The first is another `use`. We bring a type called +`std::cmp::Ordering` into scope. Then we add five new lines at the bottom that +use that type: + +```rust,ignore +match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), +} +``` + +The `cmp()` method can be called on anything that can be compared, and it +takes a reference to the thing you want to compare it to. It returns the +`Ordering` type we `use`d earlier. We use a [`match`][match] statement to +determine exactly what kind of `Ordering` it is. `Ordering` is an +[`enum`][enum], short for ‘enumeration’, which looks like this: + +```rust +enum Foo { + Bar, + Baz, +} +``` + +[match]: match.html +[enum]: enums.html + +With this definition, anything of type `Foo` can be either a +`Foo::Bar` or a `Foo::Baz`. We use the `::` to indicate the +namespace for a particular `enum` variant. + +The [`Ordering`][ordering] `enum` has three possible variants: `Less`, `Equal`, +and `Greater`. The `match` statement takes a value of a type and lets you +create an ‘arm’ for each possible value. An arm is made up of a pattern and the +code that we should execute if the pattern matches the value of the type. Since +we have three types of `Ordering`, we have three arms: + +```rust,ignore +match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), +} +``` + +[ordering]: ../std/cmp/enum.Ordering.html + +If it’s `Less`, we print `Too small!`, if it’s `Greater`, `Too big!`, and if +`Equal`, `You win!`. `match` is really useful and is used often in Rust. + +We did mention that this won’t quite compile yet, though. Let’s try it: + +```bash +$ cargo build + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) +src/main.rs:23:21: 23:35 error: mismatched types [E0308] +src/main.rs:23 match guess.cmp(&secret_number) { + ^~~~~~~~~~~~~~ +src/main.rs:23:21: 23:35 help: run `rustc --explain E0308` to see a detailed explanation +src/main.rs:23:21: 23:35 note: expected type `&std::string::String` +src/main.rs:23:21: 23:35 note: found type `&_` +error: aborting due to previous error +Could not compile `guessing_game`. +``` + +Whew! This is a big error. The core of it is that we have ‘mismatched types’. +Rust has a strong, static type system. However, it also has type inference. +When we wrote `let guess = String::new()`, Rust was able to infer that `guess` +should be a `String`, so it doesn’t make us write out the type. With our +`secret_number`, there are a number of types which can have a value between one +and a hundred: `i32`, a thirty-two-bit number, or `u32`, an unsigned +thirty-two-bit number, or `i64`, a sixty-four-bit number or others. So far, +that hasn’t mattered, and so Rust defaults to an `i32`. However, here, Rust +doesn’t know how to compare the `guess` and the `secret_number`. They need to +be the same type. + +Ultimately, we want to convert the `String` we read as input +into a real number type so that we can compare it to the guess numerically. We +can do that with two more lines. Here’s our new program: + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), + } +} +``` + +The new two lines: + +```rust,ignore +let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); +``` + +Wait a minute, didn't we already have a `guess`? We do, but Rust allows us +to ‘shadow’ the previous `guess` with a new one. This is often used in this +exact situation, where `guess` starts as a `String`, but we want to convert it +to a `u32`. Shadowing lets us re-use the `guess` name rather than forcing us +to come up with two unique names like `guess_str` and `guess` or something +else. + +We bind `guess` to an expression that looks like something we wrote earlier: + +```rust,ignore +guess.trim().parse() +``` + +Here, `guess` refers to the old `guess`, the one that was a `String` with our +input in it. The `trim()` method on `String`s will eliminate any white space at +the beginning and end of our string. This is important, as we had to press the +‘return’ key to satisfy `read_line()`. If we type `5` and hit return, `guess` +looks like this: `5\n`. The `\n` represents ‘newline’, the enter key. `trim()` +gets rid of this, leaving our string with only the `5`. + +The [`parse()` method on strings][parse] parses a string into some kind of +number. Since it can parse a variety of numbers, we need to give Rust a hint as +to the exact type of number we want. Hence, `let guess: u32`. The colon (`:`) +after `guess` tells Rust we’re going to annotate its type. `u32` is an +unsigned, thirty-two bit integer. Rust has a number of built-in number +types, but we’ve chosen `u32`. It’s a good default choice for a small +positive number. You'll see the other number types in Chapter XX. + +[parse]: ../std/primitive.str.html#method.parse + +Just like `read_line()`, our call to `parse()` could cause an error. What if +our string contained `A👍%`? There’d be no way to convert that to a number. As +such, we’ll do the same thing we did with `read_line()`: use the `expect()` +method to crash if there’s an error. + +Let’s try our program out! + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/guessing_game` +Guess the number! +The secret number is: 58 +Please input your guess. + 76 +You guessed: 76 +Too big! +``` + +Nice! You can see we even added spaces before our guess, and it still figured +out that we guessed 76. Run the program a few times. Verify that guessing +the secret number works, as well as guessing a number too small. + +Now we’ve got most of the game working, but we can only make one guess. Let’s +change that by adding loops! + +## Looping + +The `loop` keyword gives us an infinite loop. Let’s add that in: + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + loop { + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), + } + } +} +``` + +And try it out. But wait, didn’t we just add an infinite loop? Yup. Remember +our discussion about `parse()`? If we give a non-number answer, the program +will crash and, therefore, quit. Observe: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/guessing_game` +Guess the number! +The secret number is: 59 +Please input your guess. +45 +You guessed: 45 +Too small! +Please input your guess. +60 +You guessed: 60 +Too big! +Please input your guess. +59 +You guessed: 59 +You win! +Please input your guess. +quit +thread 'main' panicked at 'Please type a number!: ParseIntError { kind: InvalidDigit }', src/libcore/result.rs:785 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +error: Process didn't exit successfully: `target/debug/guess` (exit code: 101) +``` + +Ha! `quit` actually quits. As does any other non-number input. Well, this is +suboptimal to say the least. First, let’s actually quit when you win the game: + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + loop { + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => { + println!("You win!"); + break; + } + } + } +} +``` + +By adding the `break` line after the `You win!`, we’ll exit the loop when we +win. Exiting the loop also means exiting the program, since the loop is the last +thing in `main()`. We have another tweak to make: when someone inputs a +non-number, we don’t want to quit, we want to ignore it. We can do that +like this: + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + loop { + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + let guess: u32 = match guess.trim().parse() { + Ok(num) => num, + Err(_) => continue, + }; + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => { + println!("You win!"); + break; + } + } + } +} +``` + +These are the lines that changed: + +```rust,ignore +let guess: u32 = match guess.trim().parse() { + Ok(num) => num, + Err(_) => continue, +}; +``` + +This is how you generally move from ‘crash on error’ to ‘actually handle the +error’: by switching from `expect()` to a `match` statement. A `Result` is the +return type of `parse()`. `Result` is an `enum` like `Ordering`, but in this +case, each variant has some data associated with it. `Ok` is a success, and +`Err` is a failure. Each contains more information: in this case, the +successfully parsed integer or an error type, respectively. When we `match` an +`Ok(num)`, that pattern sets the name `num` to the value inside the `Ok` (the +integer), and the code we run just returns that integer. In the `Err` case, we +don’t care what kind of error it is, so we just use the catch-all `_` instead +of a name. So for all errors, we run the code `continue`, which lets us move to +the next iteration of the loop, effectively ignoring the errors. + +Now we should be good! Let’s try it: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/guessing_game` +Guess the number! +The secret number is: 61 +Please input your guess. +10 +You guessed: 10 +Too small! +Please input your guess. +99 +You guessed: 99 +Too big! +Please input your guess. +foo +Please input your guess. +61 +You guessed: 61 +You win! +``` + +Awesome! With one tiny last tweak, we can finish the guessing game. Can you +think of what it is? That’s right, we don’t want to print out the secret +number. It was good for testing, but it kind of ruins the game. Here’s our +final source: + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + loop { + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("failed to read line"); + + let guess: u32 = match guess.trim().parse() { + Ok(num) => num, + Err(_) => continue, + }; + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => { + println!("You win!"); + break; + } + } + } +} +``` + +## Complete! + +This project showed you a lot: `let`, `match`, methods, associated +functions, using external crates, and more. + +At this point, you have successfully built the Guessing Game! Congratulations! diff --git a/nostarch/chapter03.md b/nostarch/chapter03.md new file mode 100644 index 0000000000..9fab1ab0f2 --- /dev/null +++ b/nostarch/chapter03.md @@ -0,0 +1,1303 @@ +# Common Programming Concepts in Rust + +Let's look at concepts that appear in almost every programming language and see +how they work in Rust. Many programming languages have much in common at their +core. None of the concepts presented in this chapter are unique to Rust, but +we’ll discuss Rust’s particular syntax and conventions concerning these common +concepts. + +Specifically, we’ll be talking about variable bindings, basic types, functions, +comments, and control flow. These foundations will be in every Rust +program, and learning them early will give you a strong core to start from. + +PROD: START BOX + +Keep in mind as we get into variables and functions that the Rust language has +a set of *keywords* that have been reserved for use by the language only, much +like other languages do. This means you cannot use these words as names of +variables or functions, for example. Most of these have special meaning and we +will be using them to do various things in our Rust programs; a few have no +current functionality associated but have been reserved for functionality that +might be in the Rust language in the future. You can find a list of the +keywords in Appendix XX. + +PROD: END BOX + +## Variable Bindings and Mutability + +We mentioned in Chapter XX that by default, variable bindings are *immutable*. +This is one of many nudges that Rust's design has to encourage us to write our +code to get the most of the safety and easy concurrency that Rust has to offer. +We still have the option to make our bindings mutable, though. Let's explore +how and why Rust encourages us to favor immutability, and why we might want to +opt out of that. + +Variable bindings being immutable means that once a value is bound, you can't +change that value. To illustrate this, let's generate a new project with Cargo. +Open a terminal, and navigate to the directory you want to store your projects +in. From there, run these commands: + +```bash +$ cargo new --bin bindings +$ cd bindings +``` + +Then open *src/main.rs* and replace its code with the following: + +```rust,ignore +fn main() { + let x = 5; + println!("The value of x is: {}", x); + x = 6; + println!("The value of x is: {}", x); +} +``` + +Save and run the program using `cargo run`, and you should receive an error +message, as in this output: + +```bash +$ cargo run + Compiling bindings v0.0.1 (file:///projects/bindings) +error: re-assignment of immutable variable `x` [--explain E0384] + --> src/main.rs:4:5 +4 |> x = 6; + |> ^^^^^ +note: prior assignment occurs here + --> src/main.rs:2:9 +2 |> let x = 5; + |> ^ +``` + +This is our first example of the compiler helping us find an error in our +program! Compiler errors can be frustrating. Keep in mind that they only mean +your program isn't safely doing what you want it to do yet; they do _not_ mean +that you're not a good programmer! Experienced Rustaceans still get compiler +errors. Try to keep in mind that the Rust compiler is trying to help your +program be the very best. + +PROD: START BOX +######Extended Error Explanations + +Now that you've seen an example of a Rust error, let's look at one particularly +useful aspect of errors. Rust encourages you to seek further information on the +kind of error you've received with output like this: + +```bash +error: re-assignment of immutable variable `x` [--explain E0384] +``` + +This tells us that if we pass the `--explain` flag to `rustc` with the provided +error code, we can see an extended explanation which will try to explain common +causes of and solutions to that kind of error. Not every error has a longer +explanation, but many do. Here’s the explanation for the `E0384` error we +received: + +````bash +$ rustc --explain E0384 +This error occurs when an attempt is made to reassign an immutable variable. +For example: + +``` +fn main(){ + let x = 3; + x = 5; // error, reassignment of immutable variable +} +``` + +By default, variables in Rust are immutable. To fix this error, add the keyword +`mut` after the keyword `let` when declaring the variable. For example: + +``` +fn main(){ + let mut x = 3; + x = 5; +} +``` +```` + +These explanations can really help if you’re stuck on an error, so don't +hesitate to look up the error code. The compiler is your friend, and it's there +to help. + +PROD: END BOX + +The error includes the message `re-assigment of immutable variable` because the +program tried to assign a second value to the `x` variable. + +Getting compile-time errors when your code attempts to change a value that it +previously said was immutable is important because this very situation can lead +to bugs. If one part of your code operates on an assumption that a value it's +operating on will never change, and another part of your code changes that +value, it's possible that the first code won't do what it was designed to do. +Especially when the second piece of code only changes the value _sometimes_, +this cause of bugs can be difficult to track down after the fact. + +In Rust, our code can know that a value our code assumes won't change really +won't change, because the compiler is enforcing that guarantee for us. When +reading and writing code, we don't have to keep track in our head how and where +a value might change. This can make code easier to reason about. + +Mutability is really useful, though! Bindings are immutable only by default; +you can make them mutable by adding `mut` in front of the variable name. In +addition to telling the compiler it should allow this value to be changed, it +conveys intent to future readers of the code and says that other parts of the +code will be changing this value. + +For example, change the program you just wrote to the following: + +```rust +fn main() { + let mut x = 5; + println!("The value of x is: {}", x); + x = 6; + println!("The value of x is: {}", x); +} +``` + +Running this, we get: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) + Running `target/debug/bindings` +The value of x is: 5 +The value of x is: 6 +``` + +Using `mut`, we are allowed to change the value that `x` binds to from `5` to +`6`. You might want to make a binding mutable because it makes the code easier +to understand than an implementation that only uses immutable bindings. In +cases where you're using large data structures, mutating an instance in place +may be faster than copying and returning newly allocated instances. It all +depends on the tradeoffs you want to make in your situation. + +### Shadowing + +As we saw in the guessing game tutorial, we can declare new bindings with the +same name as a previous binding, and the new binding *shadows* the previous +binding. We say that the first binding is ‘shadowed’ by the second, which means +that the second binding's value is what you will see when you use the variable +after the second binding. This can be useful if you’d like to perform a few +transformations on a value, but have the binding be immutable after those +transformations have been completed. For example: + +```rust +fn main() { + let x = 5; + + let x = x + 1; + + let x = x * 2; + + println!("The value of x is: {}", x); +} +``` + +This program first binds `x` to a value of `5`. Then, it shadows `x` by saying +`let x =` again, taking the original value and adding `1` so that the value of +`x` is then `6`. The third `let` statement also shadows `x`, taking the +previous value and multiplying it by `2` to give `x` a final value of `12`. If +you run this, it will output: + +```bash +$ cargo run + Compiling bindings v0.1.0 (file:///projects/bindings) + Running `target/debug/bindings` +The value of x is: 12 +``` + +Shadowing is useful because it lets us modify `x` without having to make the +binding mutable. This means the compiler will still keep us from accidentally +trying to mutate `x` directly later. + +Now let's look at some of the types of values that we can bind variables to. + +## Data Types + +Every value in Rust is of a certain *type*, which tells Rust what kind of data +is being given so it knows how to work with that data. In this section, we'll +look at a number of types built into the language itself split into two subsets +of Rust data types: scalar and compound. + +Something to keep in mind throughout this section: Rust is a *statically typed* +language, which means that it must know the types of all bindings at compile +time. The compiler can usually infer what type we want to use based on the +value and how we use it. When many types are possible, such as when we +converted a `String` to a numeric type using `parse()` in the guessing game +tutorial, we can add a type annotation, like this: + +```rust,ignore +let x: i32 = 5; +``` + +You will see some type annotations as we discuss the various data types. + +### Scalar Types + +A *scalar* type is one that represents a single value. There are four key +scalar types in Rust: integers, floating point numbers, booleans, and +characters. You'll likely recognize these from other programming languages, but +let's jump into how they work in Rust. + +#### Integer Types + +An *integer* is a number without a fractional component. We've used one integer +type already in this chapter, the `i32` type. This type declaration indicates +that the value it's associated with should be a signed integer (hence the `i`, +as opposed to a `u` for unsigned) for a 32-bit system. There are a number of +built-in integer types in Rust, shown in Table 3-1. + +| Length | signed | unsigned | +|--------|--------|----------| +| 8-bit | i8 | u8 | +| 16-bit | i16 | u16 | +| 32-bit | i32 | u32 | +| 64-bit | i64 | u64 | +| arch | isize | usize | + +*Table 4-1: Integer types in Rust. Each code (for example, i32) can be used to +declare the type of a value.* + +Each variant can be either signed or unsigned and has an explicit size. Signed +and unsigned merely refers to whether it is possible for the number to be +either negative or positive, meaning the number needs to have a sign with it +("signed"), or whether it will only ever be positive and can therefore be +represented without a sign ("unsigned"). It's like writing numbers on paper: +when the sign matters, a number is shown with a plus sign or minus sign, but +when it's safe to assume the number is positive, it's shown with no sign. +Signed numbers are stored using two’s complement representation (if you're +unsure what this is you can search for it online; an explanation is outside the +scope of this text). + +Finally, the `isize` and `usize` types depend on the kind of computer your +program is running on: 64-bits if you're on a 64-bit architecture, and 32-bits +if you’re on a 32-bit architecture. + +So how do you know which type of integer to use? If you're unsure, Rust's +defaults are generally good choices, and integer types default to `i32`: it’s +generally the fastest, even on 64-bit systems. The primary situation in which +you'd need to specify `isize` or `usize` is when indexing some sort of +collection, which we'll talk about in the "Arrays" section. + +#### Floating-Point Types + +Rust also has two primitive types for *floating-point numbers*, which are +numbers with decimal points. Rust's floating-point types are `f32` and `f64`, +which are 32 bits and 64 bits in size, respectively. The default type is `f64`, +as it’s roughly the same speed as `f32`, but has a larger precision. It is +possible to use an `f64` on 32 bit systems, but it will be slower than using an +`f32` on those systems. Most of the time, trading potential worse performance +for better precision is a reasonable initial choice, and you should benchmark +your code if you suspect floating-point size is a problem in your case. + +Here's an example showing floating-point numbers in action: + +```rust +fn main() { + let x = 2.0; // f64 + + let y: f32 = 3.0; // f32 +} +``` + +Floating-point numbers are represented according to the IEEE-754 standard. The +`f32` type is a single-precision float, while `f64` has double-precision. + +#### Numeric Operations + +Rust supports the usual basic mathematic operations you’d expect for all of +these number types: addition, subtraction, multiplication, division, and +modulo. This code shows how you'd use each one in a `let` statement: + +```rust +fn main() { + // addition + let sum = 5 + 10; + + // subtraction + let difference = 95.5 - 4.3; + + // multiplication + let product = 4 * 30; + + // division + let quotient = 56.7 / 32.2; + + // modulo + let remainder = 43 % 5; +} +``` + +Each expression in these statements uses a mathematical operator and evaluates +to a single value, which is then bound to a variable. + +#### The Boolean Type + +As in most other programming languages, a boolean type in Rust has two possible +values: `true` and `false`. The boolean type in Rust is specified with `bool`. +For example: + +```rust +fn main() { + let t = true; + + let f: bool = false; // with explicit type annotation +} +``` + +The main way to consume boolean values is through conditionals like an `if` +statement. We’ll cover how `if` statements work in Rust in the "Control Flow" +section of this chapter. + +#### The Character Type + +So far we’ve only worked with numbers, but Rust supports letters too. Rust’s +`char` type is the language's most primitive alphabetic type, and this code +shows one way to use it: + +```rust +fn main() { + let c = 'z'; + let z = 'ℤ'; + let heart_eyed_cat = '😻'; +} +``` + +Rust’s `char` represents a Unicode Scalar Value, which means that it can +represent a lot more than just ASCII. Accented letters, Chinese/Japanese/Korean +ideographs, emoji, and zero width spaces are all valid `char`s in Rust. Unicode +Scalar Values range from `U+0000` to `U+D7FF` and `U+E000` to `U+10FFFF` +inclusive. A "character" isn’t really a concept in Unicode, however, so your +human intuition for what a "character" is may not match up with what a `char` +is in Rust. It also means that `char`s are four bytes each. You can learn more +about Unicode Scalar Values at +*http://www.unicode.org/glossary/#unicode_scalar_value* and find a chart for +all unicode code points at *http://www.unicode.org/charts/*. + +### Compound Types + +*Compound types* can group multiple values of other types into one type. Rust +has two primitive compound types: tuples and arrays. + +#### Grouping Values into Tuples + +We’ve seen tuples already, when binding multiple values at once. A tuple is a +general way of grouping together some number of other values with distinct +types into one compound type. + +We create a tuple by writing a comma-separated list of values inside +parentheses. Each position in the tuple has a distinct type, as in this example: + +```rust +fn main() { + let tup: (i32, f64, u8) = (500, 6.4, 1); +} +``` + +Note that, unlike the examples of multiple bindings, here we bind the single +name `tup` to the entire tuple, emphasizing the fact that a tuple is considered +a single compound element. We could then use pattern matching to destructure +this tuple value, like this: + +```rust +fn main() { + let tup: (i32, f64, u8) = (500, 6.4, 1); + + let (x, y, z) = tup; + + println!("The value of y is: {}", y); +} +``` + +In this program, we first create a tuple and bind it to the name `tup`. We then +use a pattern with `let` to take `tup` and turn it into three separate +bindings, `x`, `y`, and `z`. This is called ‘destructuring’, because it breaks +the single tuple into three parts. + +Finally, we print the value of `y`, which is `6.4`. + +#### Tuple Indexing + +In addition to destructuring through pattern matching, we can also access a +tuple element directly by using a period (`.`) followed by the index of the +value we want to access. For example: + +```rust +fn main() { + let x: (i32, f64, u8) = (500, 6.4, 1); + + let five_hundred = x.0; + + let six_point_four = x.1; + + let one = x.2; +} +``` + +This program creates a tuple, `x`, and then makes new bindings to each element +by using their index. As with most programming languages, the first index in a +tuple is 0. + +### Arrays + +Another way to bind a name to a collection of multiple values is with an +*array*. Unlike a tuple, every element of an array must have the same type. +Arrays in Rust are different than arrays in some other languages because arrays +in Rust have a fixed length-- once declared, they cannot grow or shrink in size. + +In Rust, the values going into an array are written as a comma separated list +inside square brackets: + +```rust +fn main() { + let a = [1, 2, 3, 4, 5]; +} +``` + +While arrays can be useful since they are a primitive type, they aren't as +flexible as the `Vec` (short for "vector"), a similar collection type provided +by the standard library that _is_ allowed to grow or shrink in size. If you're +unsure whether to use an array or a `Vec`, you should probably go with a `Vec`, +and we'll discuss them in more detail in chapter XX. + +#### Accessing Array Elements + +An array is a single chunk of memory, allocated on the stack. We can access +elements of an array using indexing, like this: + +```rust +fn main() { + let a = [1, 2, 3, 4, 5]; + + let first = a[0]; + let second = a[1]; +} +``` + +In this example, the `first` variable will bind to `1` at index `[0]` in the +array, and `second` will bind to `2` at index `[1]` in the array. Note that +these values are copied out of the array and into `first` and `second` when the +`let` statement is called. That means if the array changes after the `let` +statements, these bindings will not, and the two variables should retain their +values. + +#### Invalid array element access + +What happens if you try to access an element of an array past the end of the +array? Say we changed our program to: + +```rust,ignore +fn main() { + let a = [1, 2, 3, 4, 5]; + + let element = a[10]; + + println!("The value of element is: {}", element); +} +``` + +Running this code with `cargo run` produces: + +```bash +$ cargo run + Compiling arrays v0.1.0 (file:///projects/arrays) + Running `target/debug/arrays` +thread '
' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:4 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +error: Process didn't exit successfully: `target/debug/arrays` (exit code: 101) +``` + +We can see that compiling did not give us any errors, but we got a *runtime* +error and our program didn't exit successfully. When we attempt to access an +element using indexing, Rust will check that the index we've specified is less +than the array length. If the index is greater than the length, it will +"panic", which is what it's called when a Rust program exits with an error. + +This is our first example of Rust’s safety principles in action. In many +low-level languages, this kind of check is not done, and when you provide an +incorrect index, invalid memory can be accessed. Rust protects us against this +kind of error by immediately exiting instead of allowing the memory access and +continuing. We'll discuss more of Rust’s error handling in Chapter XX. + +## How Functions Work + +Functions are pervasive in Rust code. We’ve already seen one of the most +important functions in the language: the `main()` function that’s the entry +point of many programs. We've also seen the `fn` keyword, which allows us to +declare new functions. + +Rust code uses *snake case* as the conventional style for function names. In +snake case, all letters are lower case, and there are underscores separating +words. (Rust also uses snake case for the names of variable bindings; we just +haven't used any variable bindings with enough letters to need underscores +yet). Here's a program containing an example function definition: + +```rust +fn main() { + println!("Hello, world!"); + + another_function(); +} + +fn another_function() { + println!("Another function."); +} +``` + +Function definitions in Rust start with `fn` and have a set of parentheses +after the function name. The curly braces tell the compiler where the function +body begins and ends. + +We can call any function we’ve defined by entering its name followed by a pair +of parentheses. Since `another_function()` is defined in the program, it can be +called from inside the `main()` function. Note that we defined +`another_function()` _after_ the `main()` function in our source code; we could +have defined it before as well. Rust doesn’t care where you define your +functions, only that they are defined somewhere. + +Let’s start a new project to explore functions further. Open a terminal, and +navigate to the directory you're keeping your projects in. From there, use +Cargo to generate a new project, as follows: + +```bash +$ cargo new --bin functions +$ cd functions +``` + +Place the `another_function()` example in a file named *src/main.rs* and run +it. You should see the following output: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +Hello, world! +Another function. +``` + +The lines execute in the order they appear in the `main()` function. First, our +“Hello, world!” message prints, and then `another_function()` is called and its +message is printed. + +### Function Arguments + +Functions can also take arguments. The following rewritten version of +`another_function()` shows what arguments look like in Rust: + +```rust +fn main() { + another_function(5); +} + +fn another_function(x: i32) { + println!("The value of x is: {}", x); +} +``` + +Try running this program, and you should get this output: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +The value of x is: 5 +``` + +Since we passed `5` to `another_function()`, the `println!` macro put `5` where +the pair of curly braces were in the format string. The declaration of +`another_function()` shows that it takes one argument named `x`, and the type +of `x` is `i32`. + +In function signatures, we _must_ declare the type. This is a deliberate +decision in the design of Rust; requiring type annotations in function +definitions means the compiler almost never needs you to use them elsewhere in +the code in order to figure out what you mean. + +When you want a function to have multiple arguments, just separate them inside +the function signature with commas, like this: + +```rust +fn main() { + another_function(5, 6); +} + +fn another_function(x: i32, y: i32) { + println!("The value of x is: {}", x); + println!("The value of y is: {}", y); +} +``` + +In this example, we make a function with two arguments, both of which are +`i32`s. If your function has multiple arguments, they don’t need to be the same +type, but they just happen to be in this example. Our function then prints out +the values of both of its arguments. + +Let’s try out this code. Replace the program currently in your `function` +project's `main.rs` file with the example above, and run it as follows: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +The value of x is: 5 +The value of y is: 6 +``` + +Since `5` is passed as the `x` argument and `6` is passed as the `y` argument, +the two strings are printed with these values. + +### Function Bodies + +Function bodies are made up of a series of statements ending in an optional +expression. So far, we've only seen functions without an ending expression, but +we have seen expressions as parts of statements. Since Rust is an +expression-based language, this is an important distinction to understand. +Other languages don't have the same distinctions, so let's look at what +statements and expressions are and how their differences affect the bodies of +functions. + +#### Statements and Expressions + +We've already been using both statements and expressions. *Statements* are +instructions that perform some action and do not return a value. *Expressions* +evaluate to a resulting value. Let's look at some examples. + +`Let` bindings are statements. They instruct the program to create a binding +name and assign a value to it. `let y = 6;` in this example is a statement: + +```rust +fn main() { + let y = 6; +} +``` + +Function definitions are also statements-- so the entire previous example is a +statement as well. + +Statements do not return values themselves. Therefore, you can’t assign a `let` +binding to another binding, as this code tries to do: + +```rust,ignore +fn main() { + let x = (let y = 6); +} +``` + +If we were to run this program, we’d get an error like this: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) +error: expected expression, found statement (`let`) + --> src/main.rs:2:14 +2 |> let x = (let y = 6); + |> ^^^ +note: variable declaration using `let` is a statement + +error: aborting due to previous error +error: Could not compile `functions`. +``` + +The `let y = 6` statement does not return a value, so there isn't anything for +`x` to bind to. This is different than in other languages like C and Ruby where +the assignment returns the value of the assignment. In those languages, you +could write `x = y = 6` and have both `x` and `y` have the value `6`, but that +is not the case in Rust. + +Expressions are most of the rest of the code that you will write in Rust. +Consider a simple math operation, like this: + +```rust,ignore +5 + 6 +``` + +This is an expression, and evaluating it results in the value `11`. Expressions +can be part of statements-- in the previous example that had the statement `let +y = 6;`, `6` is an expression that evaluates to the value `6`. Calling a +function is an expression. Calling a macro is an expression. The block that we +use to create new scopes, `{}`, is an expression, for example: + +```rust +fn main() { + let x = 5; + + let y = { + let x = 3; + x + 1 + }; + + println!("The value of y is: {}", y); +} +``` + +The expression: + +```rust,ignore +{ + let x = 3; + x + 1 +} +``` + +is a block that, in this case, gets evaluated to `4`, which then gets bound to +`y` as part of the `let` statement. + +Note that the line containing `x + 1` does not have a semicolon at the end like +most of the lines we've seen up until now have had. This is the most important +distinction between expressions and statements to remember: statements end in +semicolons while expressions do not. If you add a semicolon to the end of an +expression, that will turn it into a statement, which will then not return a +value. Keep this in mind as we explore function return values and expressions. + +### Functions with Return Values + +Functions can return values back to the code that calls them. We don’t name +return values, but we do declare their type, after an arrow (`->`). In Rust, +the "return value of the function” is synonymous with “the value of the final +expression in the block of the body of a function.” Here's an example of a +function that returns a value: + +```rust +fn five() -> i32 { + 5 +} + +fn main() { + let x = five(); + + println!("The value of x is: {}", x); +} +``` + +There are no function calls, macros, or even `let` statements in the `five()` +function-- just the number `5` by itself. That's a perfectly valid function in +Rust. Note the function's return type, too. Try running this code, and the +output should look like this: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +The value of x is: 5 +``` + +The `5` in `five()` is actually the function's return value, which is why the +return type is `i32`. Let’s examine this in more detail. There are two +important bits. First, the line `let x = five();` in `main()` shows that we can +use the return value of a function to initialize a binding. + +Because the function `five()` returns a `5`, that line is the same as saying: + +```rust +let x = 5; +``` + +The second interesting bit is the `five()` function itself. It requires no +arguments and defines the type of the return value, but the body of the +function is a lonely `5` with no semicolon because it is an expression whose +value we want to return. Let's look at another example: + +```rust +fn main() { + let x = plus_one(5); + + println!("The value of x is: {}", x); +} + +fn plus_one(x: i32) -> i32 { + x + 1 +} +``` + +Running this code will print `The value of x is: 6`. What happens if we put a +semicolon at the end of the line containing `x + 1`, changing it from an +expression to a statement? + +```rust,ignore +fn main() { + let x = plus_one(5); + + println!("The value of x is: {}", x); +} + +fn plus_one(x: i32) -> i32 { + x + 1; +} +``` + +Running this code gives an error, as follows: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) +error: not all control paths return a value [--explain E0269] + --> src/main.rs:7:1 +7 |> fn plus_one(x: i32) -> i32 { + |> ^ +help: consider removing this semicolon: + --> src/main.rs:8:10 +8 |> x + 1; + |> ^ + +error: aborting due to previous error +error: Could not compile `functions`. +``` + +The main error message, "not all control paths return a value", reveals the +core of the issue with this code. The definition of the function `plus_one` +says that it will return an `i32`, but statements don’t evaluate to a value. +Therefore, nothing is returned, which contradicts the function definition and +results in an error. In this output, Rust gives an option to rectify this: it +suggests removing the semicolon, which would fix the error. + +## Comments + +All programmers strive to make their code easy to understand, but sometimes +extra explanation is warranted. In these cases, we leave notes in our source +code that the compiler will ignore but people reading the source code may find +useful. These notes are called *comments*. + +Here’s a simple comment: + +```rust +// Hello, world. +``` + +In Rust, comments must start with two slashes and will last until the end of +the line. For comments that extend beyond a single line, you'll need to +include `//` on each line, like this: + +```rust +// So we’re doing something complicated here, long enough that we need +// multiple lines of comments to do it! Whew! Hopefully, this comment will +// explain what’s going on. +``` + +Comments can also be placed at the end of lines of code: + +```rust +fn main() { + let lucky_number = 7; // I’m feeling lucky today. +} +``` + +But you’ll more often see them above, like so: + +```rust +fn main() { + // I’m feeling lucky today. + let lucky_number = 7; +} +``` + +That’s all there is to it. Comments are not particularly complicated. + +## Control Flow + +Deciding whether or not to run some code depending on if a condition is true, +or deciding to run some code repeatedly while a condition is true, are basic +building blocks in most programming languages. The most common constructs that +let us control the flow of execution of our Rust code are `if` expressions and +loops. + +### `if` Expressions + +An `if` expression allows us to branch our code depending on conditions. We +provide a condition and then say, "If this condition is met, then run this +block of code. If the condition is not met, do not run this block of code." + +Let’s make a new project to explore `if`. Navigate to your projects directory, +and use Cargo to make a new project called `branches`: + +```bash +$ cargo new --bin branches +$ cd branches +``` + +Write this sample program using `if` and save it in the *branches* directory in +`src/main.rs`: + +```rust +fn main() { + let number = 3; + + if number < 5 { + println!("condition was true"); + } else { + println!("condition was false"); + } +} +``` + +All `if` expressions start with `if`, which is followed by a condition. In this +case, our condition is checking if our variable binding `number` has a value +that is less than 5. The block of code we want to execute if the condition is +true goes immediately after the condition, inside curly braces. These blocks +are sometimes called ‘arms’. We can optionally also include an `else` +statement, which we have chosen to do here. `else` gives the program a block of +code to execute should `condition` evaluate to false. + +Try running this code, and you should see output like this: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +condition was true +``` + +Let’s try changing the value of `number` to a value that makes the condition +`false` to see what happens: + +```rust,ignore +let number = 7; +``` + +Run the program again, and look at the output: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +condition was false +``` + +It’s also worth noting that `condition` here _must_ be a `bool`. To see what +happens if the condition isn't a `bool`, try running this code: + +```rust,ignore +fn main() { + let number = 3; + + if number { + println!("number was three"); + } +} +``` + +The `if` condition evaluates to a value of `3` this time, and Rust will +complain about it: + +```bash + Compiling branches v0.1.0 (file:///projects/branches) +error: mismatched types [--explain E0308] + --> src/main.rs:4:8 +4 |> if number { + |> ^^^^^^ expected bool, found integral variable +note: expected type `bool` +note: found type `_` + +error: aborting due to previous error +Could not compile `branches`. +``` + +The error tells us that Rust expected a `bool`, but got an integer. Rust will +not automatically try to convert non-boolean types to a boolean here, unlike +languages like Ruby or JavaScript. We must be explicit and always give `if` a +`boolean` as its condition. If your intention is for the `if` code block to be run if a number is not equal to `0`, for example, we would change the `if` expression to read: + +```rust +fn main() { + let number = 3; + + if number != 0 { + println!("number was something other than zero"); + } +} +``` + +Running this will print "number was something other than zero". + +#### Multiple Conditions with `else if` + +We can have multiple coniditions by combining `if` and `else` in an `else if` +expression. For example: + +```rust +fn main() { + let number = 5; + + if number == 3 { + println!("condition was 3"); + } else if number == 4 { + println!("condition was 4"); + } else if number == 5 { + println!("condition was 5"); + } else { + println!("condition was something else"); + } +} +``` + +This program has four possible paths it can take. If you try running it, you +should see output like this: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +condition was 5 +``` + +When this program executes, it will check each `if` expression in turn and +execute the first body for which the condition holds true. + +Using too many `else if` expressions can clutter your code, so if you find +yourself with more than one, you may want to look at refactoring your code. In +Chapter XX, we'll talk about a powerful Rust branching construct called `match` +for these cases. + +#### Using `if` in a Binding + +The last detail you need to learn about `if` is that it’s an expression. That +means that we can use it on the right hand side of a `let` binding, for +instance: + +```rust +fn main() { + let condition = true; + let number = if condition { + 5 + } else { + 6 + }; + + println!("The value of number is: {}", number); +} +``` + +The `number` variable will be bound to a value based on the outcome of the `if` +expression. Let’s run this to see what happens: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +The value of number is: 5 +``` + +Remember, blocks of code evaluate to the last expression in them, and numbers +by themselves are also expressions. In this case, the value of the whole `if` +expression depends on which block of code executes. This means that the value +that results from both arms of the `if` must be the same type; in the previous +example, they were both `i32` integers. But what happens if the types are +mismatched, as in the following example? + +```rust,ignore +fn main() { + let condition = true; + + let number = if condition { + 5 + } else { + "six" + }; + + println!("The value of number is: {}", number); +} +``` + +The expression in the `if` block is an integer and the expresion in the `else` +block is a string. This can’t work, because variable bindings must have a +single type. If we try to run this, we’ll get an error: + +```bash + Compiling branches v0.1.0 (file:///projects/branches) +src/main.rs:4:18: 8:6 error: if and else have incompatible types: + expected `_`, + found `&‘static str` +(expected integral variable, + found &-ptr) [E0308] +src/main.rs:4 let number = if condition { +src/main.rs:5 5 +src/main.rs:6 } else { +src/main.rs:7 "six" +src/main.rs:8 }; +src/main.rs:4:18: 8:6 help: run `rustc --explain E0308` to see a detailed explanation +error: aborting due to previous error +Could not compile `branches`. +``` + +The `if` and `else` arms have value types that are incompatible, and Rust tells +us exactly where to find the problem in our program. + +### Repetition with Loops + +It’s often useful to be able to execute a block of code more than one time. For +this, Rust has several constructs called *loops*. A loop runs through the code +inside it to the end and then starts immediately back at the beginning. To try +out loops, let’s make a new project. Navigate to your *projects* folder and use +Cargo to make a new project: + +```bash +$ cargo new --bin loops +$ cd loops +``` + +There are three kinds of loops in Rust: `loop`, `while`, and `for`. Let’s dig +in. + +#### Repeating Code with `loop` + +The `loop` keyword tells Rust to execute a block of code over and over again +forever or until we explicitly tell it to stop. + +For an example, change the *src/main.rs* file in your *loops* directory to look +like this: + +```rust,ignore +fn main() { + loop { + println!("again!"); + } +} +``` + +If we run this program, we’ll see `again!` printed over and over continuously +until we stop the program manually. Most terminals support a keyboard shortcut, +`control-c`, to halt a program stuck in a continual loop. Give it a try: + +```bash +$ cargo run + Compiling loops v0.1.0 (file:///projects/loops) + Running `target/debug/loops` +again! +again! +again! +again! +^Cagain! +``` + +That `^C` there is where we hit `control-c`. You may or may not see "again!" +printed after the `^C`, depending on where the code was in the loop when it +received the signal to halt. + +Fortunately, Rust provides another, more reliable way to break out of a loop. +We can place the `break` keyword within the loop to tell the program when to +stop executing the loop. Recall that we did this in the guessing game to exit +the program when the user won the game by guessing the number correctly. + +#### Conditional Loops With `while` + +A useful thing that many programs do is have a condition that can be evaluated +within a loop. While the condition is true, the loop runs. When the condition +ceases to be true, we call `break`, stopping the loop. This could be +implemented with a combination of `loop`, `if`, `else`, and `break`; try to do +that now if you'd like! + +But this pattern is so common that Rust has a more efficient language construct +for it, called a `while` loop. Here's an example using `while`: this program +loops three times, counting down each time. Finally, after the loop, it prints +another message, then exits: + +```rust +fn main() { + let mut number = 3; + + while number != 0 { + println!("{}!", number); + + number = number - 1; + } + + println!("LIFTOFF!!!"); +} +``` + +This gets rid of a lot of nesting that would be necessary if we used `loop`, +`if`, `else`, and `break`, and it's more clear. While a condition holds, run +this code; otherwise, exit the loop. + +#### Looping Though a Collection with `for` + +We could use this `while` construct to loop over the elements of a collection, +like an array. For example: + +```rust +fn main() { + let a = [10, 20, 30, 40, 50]; + let mut index = 0; + + while index < 5 { + println!("the value is: {}", a[index]); + + index = index + 1; + } +} +``` + +Here, we're counting up through the elements in the array. We start at index 0, +then loop until we hit the final index of our array (that is, when `index < 5` +is no longer true). Running this will print out every element of the array: + +```bash +$ cargo run + Compiling loops v0.1.0 (file:///projects/loops) + Running `target/debug/loops` +the value is: 10 +the value is: 20 +the value is: 30 +the value is: 40 +the value is: 50 +``` + +All five array values appear in the terminal, as expected. Even though `index` +will reach a value of `6` at some point, the loop stops executing before trying +to fetch a sixth value from the array. + +This approach is error-prone, though; we could cause our program to panic by +getting the index length incorrect. It's also slow, as the compiler needs to +perform the conditional check on every element on every iteration through the +loop. + +As a more efficient alternative, we can use a `for` loop and execute some code +for each item in a collection. A `for` loop looks like this: + +```rust +fn main() { + let a = [10, 20, 30, 40, 50]; + + for element in a.iter() { + println!("the value is: {}", element); + } +} +``` + +If we run this, we'll see the same output as the previous example. Importantly, +though, we've now increased the safety of our code and eliminated the chance of +bugs resulting from going beyond the end of the array or not going far enough +and missing some items. + +For example, in the previous code that uses the `while` loop, if we removed an +item from the `a` array but forgot to update the condition to be `while index < +4`, our code would panic. Using the `for` loop means we would not need to +remember to change any other code if we changed the the number of values in the +array. + +If you're wondering about the `.iter()` code in this example, keep reading! We +will cover method syntax generally in Chapter XX and iterators specifically in +Chapter XX. + +The safety and conciseness of `for` loops make them the most commonly used loop +construct in Rust. Even in situations where you want to run some code a certain +number of times, like our countdown example that used a `while` loop, most +Rustaceans would use a `for` loop. The way to do that is using a `Range`, which +is a type provided by the standard library that generates numbers starting from +one number and ending before another number. Here's what the countdown would +look like with a for loop, and using another method we haven't yet talked +about, `.rev()`, to reverse the range: + +```rust +fn main() { + for number in (1..4).rev() { + println!("{}!", number); + } + println!("LIFTOFF!!!"); +} +``` + +That's a bit nicer, isn't it? + +Now that you know how Rust does things that most other languages can do, let's +talk about a concept that _doesn't_ commonly exist: ownership. diff --git a/nostarch/chapter4.md b/nostarch/chapter04.md similarity index 54% rename from nostarch/chapter4.md rename to nostarch/chapter04.md index 6e5dcf0e74..16753d8ae6 100644 --- a/nostarch/chapter4.md +++ b/nostarch/chapter04.md @@ -1,49 +1,52 @@ -# Ownership +# Understanding Ownership + +Ownership is important to understand: it's Rust's most unique feature, and +enables Rust to make memory safety guarantees without needing a garbage +collector. We’ll also talk about several related features: borrowing, slices, +and how Rust lays things out in memory. + +## Ownership Rust’s central feature is called ‘ownership’. It is a feature that is straightforward to explain, but has deep implications for the rest of the -language. +language. -Rust is committed to both safety and speed. One of the key tools for balancing -between them is “zero-cost abstractions”: the various abstractions in Rust do -not pose a global performance penalty. The ownership system is a prime example -of a zero-cost abstraction. All of the analysis we’ll talk about in this guide -is done at compile time. You do not pay any run-time cost for any of these +All programs have to manage the way they use a computer's memory while running. +Some languages have garbage collection, while in others, the programmer has to +explicitly allocate and free the memory. Rust takes a third approach: memory is +managed through a system of ownership with a set of rules that the compiler +checks at compile-time. You do not pay any run-time cost for any of these features. -However, this system does have a certain cost: learning curve. Many new -Rustaceans experience something we like to call ‘fighting with the borrow -checker’, where the Rust compiler refuses to compile a program that the author -thinks is valid. This can happen because the programmer isn’t used to thinking -carefully about ownership, or is thinking about it differently from the way -that Rust does. You probably will experience something similar at first. There is -good news, however: more experienced Rust developers report that once they work -with the rules of the ownership system for a period of time, they fight the -borrow checker less and less. Keep at it! +However, because ownership is a new concept for many programmers, it does take +some time to get used to. There is good news, though: the more experienced you +become with Rust and the rules of the ownership system, the more you'll be +able to naturally develop code that is both safe and efficient. Keep at it! -This chapter will give you a foundation for understanding the rest of the -language. To do so, we’re going to learn through examples, focusing on a very -common data structure: strings. +Once you understand ownership, you have a good foundation for understanding the +features that make Rust unique. In this chapter, we'll learn ownership by going +through some examples, focusing on a very common data structure: strings. -## Variable binding scope +### Variable binding scope -Let’s take a step back and look at the very basics again. Now that we’re past -basic syntax, we won’t include all of the `fn main() {` stuff in examples, so -if you’re following along, you will have to put them inside of a `main()` -function. This lets our examples be a bit more concise, letting us focus on the -actual details, rather than boilerplate. +We've walked through an example of a Rust program already in the tutorial +chapter. Now that we’re past basic syntax, we won’t include all of the `fn +main() {` stuff in examples, so if you’re following along, you will have to put +them inside of a `main()` function. This lets our examples be a bit more +concise, letting us focus on the actual details rather than boilerplate. -Anyway, here it is: +Anyway, here is our first example: ```rust let s = "hello"; ``` -This variable binding refers to a string literal. It’s valid from the point at -which it’s declared, until the end of the current _scope_. That is: +This variable binding refers to a string literal, where the value of the string +is hard coded into the text of our program. The binding is valid from the point +at which it’s declared until the end of the current _scope_. That is: ```rust -{ // s is not valid here, it’s not yet in scope +{ // s is not valid here, it’s not yet declared let s = "hello"; // s is valid from this point forward // do stuff with s @@ -55,36 +58,38 @@ In other words, there are two important points in time here: - When `s` comes ‘into scope’, it is valid. - It remains so until it ‘goes out of scope’. -At this point, things are similar to other programming languages. Let’s build -on top of this understanding by introducing a new type: `String`. +At this point, things are similar to other programming languages. Now let’s +build on top of this understanding by introducing the `String` type. -## Strings +### Strings -String literals are convenient, but they aren’t the only way that you use strings. -For one thing, they’re immutable. For another, not every string is literal: -what about taking user input and storing it in a string? +String literals are convenient, but they aren’t the only way that you use +strings. For one thing, they’re immutable. For another, not every string is +literal: what about taking user input and storing it in a string? -For this, Rust has a second string type, `String`. You can create a `String` from -a string literal using the `from` function: +For this, Rust has a second string type, `String`. You can create a `String` +from a string literal using the `from` function: ```rust let s = String::from("hello"); ``` -We haven’t seen the double colon (`::`) syntax yet. It is a kind of scope -operator, allowing us to namespace this particular `from()` function under the -`String` type itself, rather than using some sort of name like `string_from()`. -We’ll discuss this syntax more in the “Method Syntax” and “Modules” chapters. +We haven’t seen the double colon (`::`) syntax yet. It is an operator that +allows us to namespace this particular `from()` function under the `String` +type itself, rather than using some sort of name like `string_from()`. We’ll +discuss this syntax more in the “Method Syntax” and “Modules” chapters. This kind of string can be mutated: ```rust let mut s = String::from("hello"); -s.push_str(", world!"); +s.push_str(", world!"); // push_str() appends a literal to a String + +println!("{}", s); // This will print `hello, world!` ``` -## Memory and allocation +### Memory and allocation So, what’s the difference here? Why can `String` be mutated, but literals cannot? The difference comes down to how these two types deal with memory. @@ -92,11 +97,13 @@ cannot? The difference comes down to how these two types deal with memory. In the case of a string literal, because we know the contents of the string at compile time, we can hard-code the text of the string directly into the final executable. This means that string literals are quite fast and efficient. But -these properties only come from its immutability; we can’t put an -arbitrary-sized blob of memory into the binary for each string! +these properties only come from its immutability. Unfortunately, we can’t put a +blob of memory into the binary for each string whose size is unknown at compile +time and whose size might change over the course of running the program. -With `String`, to support a mutable, growable string, we need to allocate an -unknown amount of memory to hold the contents. This means two things: +With `String`, in order to support a mutable, growable string, we need to +allocate an unknown amount of memory to hold the contents. This means two +things: 1. The memory must be requested from the operating system at runtime. 2. We need a way of giving this memory back to the operating system when we’re @@ -107,13 +114,15 @@ implementation requests the memory it needs. This is pretty much universal in programming languages. The second case, however, is different. In languages with a garbage collector -(‘GC’), the GC handles that second case, and we, as the programmer, don’t need -to think about it. Without GC, it’s the programmer’s responsibility to identify -when memory is no longer being used, and explicitly return it, just as it was -requested. Doing this correctly has historically been a difficult problem. If -we forget, we will waste memory. If we do it too early, we will have an invalid -variable. If we do it twice, that’s a bug too. We need to pair exactly one -`allocate()` with exactly one `free()`. +(‘GC’), the GC will keep track and clean up memory that isn't being used +anymore, and we, as the programmer, don’t need to think about it. Without GC, +it’s our responsibility to identify when memory is no longer being used and +call code to explicitly return it, just as we did to request it. Doing this +correctly has historically been a difficult problem. If we forget, we will +waste memory. If we do it too early, we will have an invalid variable. If we do +it twice, that’s a bug too. We need to pair exactly one `allocate()` with +exactly one `free()`. + Rust takes a different path. Remember our example? Here’s a version with `String`: @@ -126,22 +135,23 @@ Rust takes a different path. Remember our example? Here’s a version with } // this scope is now over, and s is no longer valid ``` -We have a natural point at which we can return the memory our `String` needs back -to the operating system: when it goes out of scope! When a variable goes out of -scope, a special function is called. This function is called `drop()`, and it -is where the author of `String` can put the code to return the memory. +We have a natural point at which we can return the memory our `String` needs +back to the operating system: when it goes out of scope. When a variable goes +out of scope, Rust calls a special function for us. This function is called +`drop()`, and it is where the author of `String` can put the code to return the +memory. -> Aside: This pattern is sometimes called “Resource Aquisition Is +> Aside: This pattern is sometimes called “Resource Acquisition Is > Initialization” in C++, or “RAII” for short. While they are very similar, > Rust’s take on this concept has a number of differences, and so we don’t tend -> to use the same term. If you’re familliar with this idea, keep in mind that it +> to use the same term. If you’re familiar with this idea, keep in mind that it > is _roughly_ similar in Rust, but not identical. This pattern has a profound impact on the way that Rust code is written. It may -seem obvious right now, but things can get tricky in more advanced situations! +seem obvious right now, but things can get tricky in more advanced situations. Let’s go over the first one of those right now. -## Move +### Move What would you expect this code to do? @@ -150,7 +160,7 @@ let x = 5; let y = x; ``` -You might say “Make a copy of `5`.” That’d be correct! We now have two +You might say “Make a copy of `5`”, and that would be correct. We now have two bindings, `x` and `y`, and both equal `5`. Now let’s look at `String`. What would you expect this code to do? @@ -164,57 +174,52 @@ You might say “copy the `String`!” This is both correct and incorrect at the same time. It does a _shallow_ copy of the `String`. What’s that mean? Well, let’s take a look at what `String` looks like under the covers: -string +string A `String` is made up of three parts: a pointer to the memory that holds the contents of the string, a length, and a capacity. The length is how much memory the `String` is currently using. The capacity is the total amount of memory the `String` has gotten from the operating system. The difference between length -and capacity matters, but not in this context, so don’t worry about it too much -if it doesn’t make sense, and just ignore the capacity. +and capacity matters but not in this context, so don’t worry about it too much. +For right now, it's fine to ignore the capacity. -> We’ve talked about two kinds of composite types: arrays and tuples. `String` -> is a third type: a `struct`, which we will cover the details of in the next -> chapter of the book. For now, thinking about `String` as a tuple is close -> enough. +When we assign `s1` to `s2`, the `String` itself is copied, meaning we copy the +pointer, the length, and the capacity. We do not copy the data that the +`String`'s pointer refers to. In other words, it looks like this: -When we assign `s1` to `s2`, the `String` itself is copied. But not all kinds -of copying are the same. Many people draw distinctions between ‘shallow -copying’ and ‘deep copying’. We don’t use these terms in Rust. We instead say -that something is ‘moved’ or ‘cloned’. Assignment in Rust causes a ‘move’. In -other words, it looks like this: - -s1 and s2 +s1 and s2 _Not_ this: -s1 and s2 to two places - -When moving, Rust makes a copy of the data structure itself, the contents of -`s1` are copied, but if `s1` contains a reference, like it does in this case, -Rust will not copy the things that those references refer to. - -There’s a problem here! Both `data` pointers are pointing to the same place. -Why is this a problem? Well, when `s2` goes out of scope, it will free the -memory that `data` points to. And then `s1` goes out of scope, and it will -_also_ try to free the memory that `data` points to! That’s bad. - -So what’s the solution? Here, we stand at a crossroads. There are a few -options. One would be to declare that assignment will also copy out any data. -This works, but is inefficient: what if our `String` contained a novel? Also, -it only works for memory. What if, instead of a `String`, we had a -`TcpConnection`? Opening and closing a network connection is very similar to -allocating and freeing memory. The solution that we could use there is to allow -the programmer to hook into the assignment, similar to `drop()`, and write code -fix things up. That would work, but now, an `=` can run arbitrary code. That’s -also not good, and it doesn’t solve our efficiency concerns either. +s1 and s2 to two places + +There’s a problem here. Both data pointers are pointing to the same place. Why +is this a problem? Well, when `s2` goes out of scope, it will free the memory +that the pointer points to. And then `s1` goes out of scope, and it will _also_ +try to free the memory that the pointer points to. That’s bad, and is known as +a "double free" error. + +So what’s the solution? Here, we stand at a crossroads with a few options. + +One way would be to change assignment so that it will also copy out any data. +This works, but is inefficient: what if our `String` contained a novel? +Also, that solution would only work for memory. What if, instead of a `String`, +we had a `TcpConnection`? Opening and closing a network connection is very +similar to allocating and freeing memory, so it would be nice to be able to use +the same mechanism. We wouldn't be able to, though, because creating a new +connection requires more than just copying memory: we have to request a new +connection from the operating system. We could then extend our solution to +allow the programmer to hook into the assignment, similar to `drop()`, and +write code to fix things up. That would work, but if we did that, an `=` could +run arbitrary code. That’s also not good, and it doesn’t solve our efficiency +concerns either. Let’s take a step back: the root of the problem is that `s1` and `s2` both -think that they have control of the memory, and therefore needs to free it. +think that they have control of the memory and therefore need to free it. Instead of trying to copy the allocated memory, we could say that `s1` is no -longer valid, and therefore, doesn’t need to free anything. This is in fact the -choice that Rust makes. Check it out what happens when you try to use `s1` -after `s2` is created: +longer valid and, therefore, doesn’t need to free anything. This is in fact the +choice that Rust makes. Check out what happens when you try to use `s1` after +`s2` is created: ```rust,ignore let s1 = String::from("hello"); @@ -225,7 +230,7 @@ println!("{}", s1); You’ll get an error like this: -```text +```bash 5:22 error: use of moved value: `s1` [E0382] println!("{}", s1); ^~ @@ -235,30 +240,38 @@ println!("{}", s1); ^~ ``` -We say that `s1` was _moved_ into `s2`. When a value moves, its data is copied, -but the original variable binding is no longer usable. That solves our problem: +If you have heard the terms "shallow copy" and "deep copy" while working with +other languages, the concept of copying the pointer, length, and capacity +without copying the data probably sounded like a shallow copy. Because Rust +also invalidates the first binding, instead of calling this a shallow copy, +it's called a _move_. Here we would read this by saying that `s1` was _moved_ +into `s2`. So what actually happens looks like this: -s1 and s2 to the same place +s1 and s2 to the same place -With only `s2` valid, when it goes out of scope, it will free the memory, and we’re done! +That solves our problem! With only `s2` valid, when it goes out of scope, it +alone will free the memory, and we’re done. -## Ownership Rules +### Ownership Rules This leads us to the Ownership Rules: -> 1. Each value in Rust has a variable binding that’s called it’s ‘owner’. +> 1. Each value in Rust has a variable binding that’s called its ‘owner’. > 2. There can only be one owner at a time. > 3. When the owner goes out of scope, the value will be `drop()`ped. Furthermore, there’s a design choice that’s implied by this: Rust will never -automatically create ‘deep’ copies of your data. Any automatic copying must be -inexpensive. +automatically create ‘deep’ copies of your data. Therefore, any _automatic_ +copying can be assumed to be inexpensive. + +### Clone -## Clone +But what if we _do_ want to deeply copy the `String`’s data and not just the +`String` itself? There’s a common method for that: `clone()`. We will discuss +methods in the section on [`structs`], but they’re a common enough feature +in many programming languages that you have probably seen them before. -But what if we _do_ want to deeply copy the `String`’s data, and not just the -`String` itself? There’s a common method for that: `clone()`. Here’s an example -of `clone()` in action: +Here’s an example of the `clone()` method in action: ```rust let s1 = String::from("hello"); @@ -267,16 +280,18 @@ let s2 = s1.clone(); println!("{}", s1); ``` +[`structs`]: ch05-01-structs.html + This will work just fine. Remember our diagram from before? In this case, it _is_ doing this: -s1 and s2 to two places +s1 and s2 to two places When you see a call to `clone()`, you know that some arbitrary code is being -executed, which may be expensive. It’s a visual indicator that something +executed, and that code may be expensive. It’s a visual indicator that something different is going on here. -## Copy +### Copy There’s one last wrinkle that we haven’t talked about yet. This code works: @@ -289,38 +304,32 @@ println!("{}", x); But why? We don’t have a call to `clone()`. Why didn’t `x` get moved into `y`? -For types that do not have any kind of complex storage requirements, like -integers, typing `clone()` is busy work. There’s no reason we would ever want -to prevent `x` from being valid here, as there’s no situation in which it’s -incorrect. In other words, there’s no difference between deep and shallow -copying here, so calling `clone()` wouldn’t do anything differently from the -usual shallow copying. - -Rust has a special annotation that you can place on types, called `Copy`. If -a type is `Copy`, an older binding is still usable after assignment. Integers -are an example of such a type; most of the primitive types are `Copy`. - -While we haven’t talked about how to mark a type as `Copy` yet, you might ask -yourself “what happens if we made `String` `Copy`?” The answer is, you cannot. -Remember `drop()`? Rust will not let you make something `Copy` if it has +Types like integers that have a known size at compile time do not ask for +memory from the operating system and therefore do not need to be `drop()`ped +when they go out of scope. That means there's no reason we would want to +prevent `x` from being valid after we create the binding `y`. In other words, +there’s no difference between deep and shallow copying here, so calling +`clone()` wouldn’t do anything differently from the usual shallow copying and +we can leave it out. + +Rust has a special annotation that you can place on types like these, and that +annotation is the `Copy` trait. We'll talk more about traits in Chapter XX. If +a type has the `Copy` trait, an older binding is still usable after assignment. +Rust will not let you make something have the `Copy` trait if it has implemented `drop()`. If you need to do something special when the value goes out of scope, being `Copy` will be an error. So what types are `Copy`? You can check the documentation for the given type to -be sure, but as a rule of thumb, any group of simple scalar values can be -Copy, but nothing that requires allocation or is some form of resource is `Copy`. -And you can’t get it wrong: the compiler will throw an error if you try to use -a type that moves incorrectly, as we saw above. - -Here’s some types that you’ve seen so far that are `Copy`: +be sure, but as a rule of thumb, any group of simple scalar values can be Copy, +but nothing that requires allocation or is some form of resource is `Copy`. Here’s some of the types that are `Copy`: * All of the integer types, like `u32`. * The booleans, `true` and `false`. * All of the floating point types, like `f64`. * Tuples, but only if they contain types which are also `Copy`. `(i32, i32)` - is `Copy`, but `(i32, String)` is not! + is `Copy`, but `(i32, String)` is not. -## Ownership and functions +### Ownership and functions Passing a value to a function has similar semantics as assigning it: @@ -374,7 +383,9 @@ fn makes_copy(some_integer: i32) { // some_integer comes into scope. ``` Remember: If we tried to use `s` after the call to `takes_ownership()`, Rust -would throw a compile-time error! These static checks protect us from mistakes. +would throw a compile-time error. These static checks protect us from mistakes. +Try adding code to `main` that uses `s` and `x` to see where you can use them +and where the ownership rules prevent you from doing so. Returning values can also transfer ownership: @@ -399,7 +410,7 @@ fn takes_and_gives_back(a_string: String) -> String { } ``` -With simililar annotations: +With similiar annotations: ```rust fn main() { @@ -435,9 +446,11 @@ fn takes_and_gives_back(a_string: String) -> String { // a_string comes into sco It’s the same pattern, every time: assigning something moves it, and when an owner goes out of scope, if it hasn’t been moved, it will `drop()`. -This might seem a bit tedious, and it is. What if I want to let a function use -a value, but not take ownership? It’s quite annoying that anything I pass in -also needs passed back. Look at this function: +This might seem a bit tedious, and it is. What if we want to let a function use +a value but not take ownership? It’s quite annoying that anything we pass in +also needs to be passed back if we want to use it again, in addition to any +data resulting from the body of the function that we might want to return as +well. It's _possible_ to return multiple values, using a tuple, like this: ```rust fn main() { @@ -455,13 +468,11 @@ fn calculate_length(s: String) -> (String, usize) { } ``` -This is too much ceremony: we have to use a tuple to give back the `String` as -well as the length. It’s a lot of work for a pattern that should be common. - -Luckily for us, Rust has such a feature, and it’s what the next section is about. - +But this is too much ceremony and a lot of work for a concept that should be +common. Luckily for us, Rust has a feature for this concept, and it’s what the +next section is about. -# References and Borrowing +## References and Borrowing At the end of the last section, we had some example Rust that wasn’t very good. Here it is again: @@ -483,7 +494,8 @@ fn calculate_length(s: String) -> (String, usize) { ``` The issue here is that we have to return the `String` back to the calling -function so that it could still use it. +function so that we can still use it there, since it was moved when we called +`calculate_length()`. There is a better way. It looks like this: @@ -503,11 +515,12 @@ fn calculate_length(s: &String) -> usize { } ``` -First, you’ll notice all of the tuple stuff is gone. Next, that we pass `&s1` -into `calculate_lengths()`. And in its definition, we take `&String` rather -than `String`. +First, you’ll notice all of the tuple stuff in the binding declaration and the +function return value is gone. Next, note that we pass `&s1` into +`calculate_length()`, and in its definition, we take `&String` rather than +`String`. -These `&s` are called ‘references’, and they allow you to refer to some value +These `&`s are called ‘references’, and they allow you to refer to some value without taking ownership of it. Here’s a diagram: DIAGRAM GOES HERE of a &String pointing at a String, with (ptr, len, capacity) @@ -517,7 +530,7 @@ Let’s take a closer look at the function call here: ```rust # fn calculate_length(s: &String) -> usize { # let length = s.len(); -# +# # length # } let s1 = String::from("hello"); @@ -525,14 +538,12 @@ let s1 = String::from("hello"); let len = calculate_length(&s1); ``` -The `&s1` syntax lets us create a reference from `s1`. This reference _refers_ -to the value of `s1`, but does not own it. Because it does not own it, the +The `&s1` syntax lets us create a reference with `s1`. This reference _refers_ +to the value of `s1` but does not own it. Because it does not own it, the value it points to will not be dropped when the reference goes out of scope. Likewise, the signature of the function uses `&` to indicate that it takes -a reference as an argument: - -Let’s add some explanatory annotations: +a reference as an argument. Let’s add some explanatory annotations: ```rust fn calculate_length(s: &String) -> usize { // s is a reference to a String @@ -549,11 +560,11 @@ This lets us write functions which take references as arguments instead of the values themselves, so that we won’t need to return them to give back ownership. There’s another word for what references do, and that’s ‘borrowing’. Just like -with real life, if I own something, you can borrow it from me. When you’re done, -you have to give it back. +with real life, if a person owns something, you can borrow it from them. When +you’re done, you have to give it back. Speaking of which, what if you try to modify something you borrow from me? Try -this code out. Spoiler alert: it doesn’t work: +this code out. Spoiler alert: it doesn’t work! ```rust,ignore fn main() { @@ -563,22 +574,24 @@ fn main() { } fn change(some_string: &String) { - some_string.push_str(", world"); // push_str() appends a literal to a String + some_string.push_str(", world"); } ``` Here’s the error: ```text -8:16 error: cannot borrow immutable borrowed content `*some_string` as mutable - some_string.push_str(", world"); // push_str() appends a literal to a String - ^~~~~~~~~~~ +error: cannot borrow immutable borrowed content `*some_string` as mutable + --> error.rs:8:5 + | +8 | some_string.push_str(", world"); + | ^^^^^^^^^^^ ``` -Just like bindings are immutable by default, so are references. We’re not allowed -to modify something we have a reference to. +Just like bindings are immutable by default, so are references. We’re not +allowed to modify something we have a reference to. -## Mutable references +### Mutable references We can fix this bug! Just a small tweak: @@ -590,12 +603,13 @@ fn main() { } fn change(some_string: &mut String) { - some_string.push_str(", world"); // push_str() appends a literal to a String + some_string.push_str(", world"); } ``` -First, we had to change `s` to be `mut`. Then, we had to create a mutable reference -with `&mut s` and accept a mutable reference with `some_string: &mut String`. +First, we had to change `s` to be `mut`. Then we had to create a mutable +reference with `&mut s` and accept a mutable reference with `some_string: &mut +String`. Mutable references have one big restriction, though. This code fails: @@ -609,28 +623,24 @@ let r2 = &mut s; Here’s the error: ```text -5:20 error: cannot borrow `s` as mutable more than once at a time [E0499] - let r2 = &mut s; - ^ -4:20 note: previous borrow of `s` occurs here; the mutable borrow prevents - subsequent moves, borrows, or modification of `s` until the borrow - ends - let r1 = &mut s; - ^ -7:2 note: previous borrow ends here -fn main() { - -} -^ +error[E0499]: cannot borrow `s` as mutable more than once at a time + --> borrow_twice.rs:5:19 + | +4 | let r1 = &mut s; + | - first mutable borrow occurs here +5 | let r2 = &mut s; + | ^ second mutable borrow occurs here +6 | } + | - first borrow ends here ``` -The error is what it says on the tin: you cannot borrow something more than -once at a time in a mutable fashion. This restriction allows for mutation, but -in a very controlled fashion. It is something that new Rustaceans struggle -with, because most languages let you mutate whenever you’d like. +The error is what it says: you cannot borrow something mutably more than once +at a time. This restriction allows for mutation but in a very controlled +fashion. It is something that new Rustaceans struggle with, because most +languages let you mutate whenever you’d like. As always, we can use `{}`s to create a new scope, allowing for multiple mutable -references. Just not _simultaneous_ ones: +references, just not _simultaneous_ ones: ```rust let mut s = String::from("hello"); @@ -643,7 +653,8 @@ let mut s = String::from("hello"); let r2 = &mut s; ``` -There is a simlar rule for combining the two kinds of references. This code errors: +There is a similar rule for combining mutable and immutable references. This +code errors: ```rust,ignore let mut s = String::from("hello"); @@ -656,27 +667,23 @@ let r3 = &mut s; // BIG PROBLEM Here’s the error: ```text -19: 6:20 error: cannot borrow `s` as mutable because it is also borrowed as - immutable [E0502] - let r3 = &mut s; // BIG PROBLEM - ^ -15: 4:16 note: previous borrow of `s` occurs here; the immutable borrow - prevents subsequent moves or mutable borrows of `s` until the - borrow ends - let r1 = &s; // no problem - ^ -8:2 note: previous borrow ends here -fn main() { - -} -^ +error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable + --> borrow_thrice.rs:6:19 + | +4 | let r1 = &s; // no problem + | - immutable borrow occurs here +5 | let r2 = &s; // no problem +6 | let r3 = &mut s; // BIG PROBLEM + | ^ mutable borrow occurs here +7 | } + | - immutable borrow ends here ``` Whew! We _also_ cannot have a mutable reference while we have an immutable one. Users of an immutable reference don’t expect the values to suddenly change out from under them! Multiple immutable references are okay, however. -## Dangling references +### Dangling references In languages with pointers, it’s easy to create a “dangling pointer” by freeing some memory while keeping around a pointer to that memory. In Rust, by @@ -701,12 +708,17 @@ fn dangle() -> &String { Here’s the error: ```text -error: missing lifetime specifier [E0106] -fn dangle() -> &String { - ^~~~~~~ -help: this function’s return type contains a borrowed value, but there is no - value for it to be borrowed from -help: consider giving it a ‘static lifetime +error[E0106]: missing lifetime specifier + --> dangle.rs:5:16 + | +5 | fn dangle() -> &String { + | ^^^^^^^ + | + = help: this function's return type contains a borrowed value, but there is no + value for it to be borrowed from + = help: consider giving it a 'static lifetime + +error: aborting due to previous error ``` This error message refers to a feature we haven’t learned about yet, @@ -747,26 +759,25 @@ fn no_dangle() -> String { This works, no problem. Ownership is moved out, nothing is deallocated. -## The Rules of References +### The Rules of References -Here’s a recap of what we’ve talked about. The Rules of References: +Here’s a recap of what we’ve talked about: 1. At any given time, you may have _either_, but not both of: 1. One mutable reference. - 2. Any number of immutable references . + 2. Any number of immutable references. 2. References must always be valid. -While these rules are not complicated on their own, they can be tricky when -applied to real code. +Next, let's look at a different kind of reference: slices. -# Slices +## Slices So far, we’ve talked about types that have ownership, like `String`, and ones -that don’t, like `&String`. There is a second kind of type which does not have +that don’t, like `&String`. There is another kind of type which does not have ownership: slices. Slices let you reference a contiguous sequence of elements -in a collection, rather than the whole collection itself. +in a collection rather than the whole collection itself. -Here’s a small programming problem: write a function which takes a string, +Here’s a small programming problem: write a function which takes a string and returns the first word you find. If we don’t find a space in the string, then the whole string is a word, so the whole thing should be returned. @@ -785,8 +796,8 @@ the word, though. Let’s try that: fn first_word(s: &String) -> usize { let bytes = s.as_bytes(); - for (i, &byte) in bytes.iter().enumerate() { - if byte == 32 { + for (i, &item) in bytes.iter().enumerate() { + if item == 32 { return i; } } @@ -797,66 +808,68 @@ fn first_word(s: &String) -> usize { Let’s break that down a bit: -```rust -fn first_word(s: &String) -> usize { +```rust,ignore +let bytes = s.as_bytes(); +``` - // Since we need to go through the String element by element, and - // check if a value is a space, we will convert our String to an - // array of bytes, using the `.as_bytes()` method. - let bytes = s.as_bytes(); +Since we need to go through the String element by element and +check if a value is a space, we will convert our String to an +array of bytes using the `.as_bytes()` method. - // We discussed using the iter() method with for in Chapter 3.7. Here, - // we’re adding another method: enumerate(). While iter() returns each - // element, enumerate() modifies the result of iter(), and returns a - // tuple instead. The first element of the tuple is the index, and the - // second element is a reference to the element itself. This is a bit - // nicer than calculating the index ourselves. - // - // Since it’s a tuple, we can use patterns, just like elsewhere in Rust. - // So we match against the tuple with i for the index, and &byte for - // the byte itself. - for (i, &byte) in bytes.iter().enumerate() { - - // 32 is the value of a space in UTF-8 - if byte == 32 { - - // We found a space! Return this position. - return i; - } - } +```rust,ignore +for (i, &item) in bytes.iter().enumerate() { +``` - // If we got here, we didn’t find a space, so this whole thing must be a - // word. So return the length. - s.len() +We will be discussing iterators in more detail in Chapter XX, but for +now, know that `iter()` is a method that returns each element in a +collection, and `enumerate()` modifies the result of `iter()` and returns +a tuple instead. The first element of the tuple is the index, and the +second element is a reference to the element itself. This is a bit +nicer than calculating the index ourselves. + +Since it’s a tuple, we can use patterns, just like elsewhere in Rust. So we +match against the tuple with i for the index and &item for a single byte. Since +we get a reference from `.iter().enumerate()`, we use `&` in the pattern. + +```rust,ignore + if item == 32 { + return i; + } } +s.len() ``` +We search for the value 32, which represents a space in UTF-8. If we find one, +we return the position. Otherwise, we return the length of the string, using +`s.len()`. + This works, but there’s a problem. We’re returning a `usize` on its own, but -it’s only a meaningful number in the context of the `&String` itself. In other +it’s only a meaningful number in the context of the `&String`. In other words, because it’s a separate value from the `String`, there’s no guarantee that it will still be valid in the future. Consider this: ```rust # fn first_word(s: &String) -> usize { # let bytes = s.as_bytes(); -# -# for (i, &byte) in bytes.iter().enumerate() { -# if byte == 32 { +# +# for (i, &item) in bytes.iter().enumerate() { +# if item == 32 { # return i; # } # } -# +# # s.len() # } fn main() { let mut s = String::from("hello world"); - let word = first_word(&s); + let word = first_word(&s); // word will get the value 5. s.clear(); // This empties the String, making it equal to "". - // word is now totally invalid! There’s no more word here. + // word still has the value 5 here, but there's no more string that + // we could meaningfully use the value 5 with. word is now totally invalid! } ``` @@ -867,13 +880,13 @@ function. Its signature would have to look like this: fn second_word(s: &String) -> (usize, usize) { ``` -Now we’re tracking both a start _and_ and ending index. Even more chances for +Now we’re tracking both a start _and_ an ending index. Even more chances for things to go wrong. We now have three unrelated variable bindings floating around which need to be kept in sync. -Luckily, Rust has a solution to this probem: string slices. +Luckily, Rust has a solution to this problem: string slices. -# String slices +## String slices A string slice looks like this: @@ -881,19 +894,25 @@ A string slice looks like this: let s = String::from("hello world"); let hello = &s[0..5]; -let world = &s[5..9]; +let world = &s[6..11]; ``` This looks just like taking a reference to the whole `String`, but with the -extra `[0..5]` bit. Instead of being a reference to the entire `String`, -it’s a reference to an internal position in the `String`, but it also keeps -track of the number of elements that it refers to as well. In other words, -it looks like this: +extra `[0..5]` bit. Instead of being a reference to the entire `String`, it’s a +reference to an internal position in the `String` and the number of elements +that it refers to. + +We can create slices with a range of `[starting_index..ending_index]`, but the +slice data structure actually stores the starting position and the length of the +slice. So in the case of `let world = &s[6..11];`, `world` would be a slice that +contains a pointer to the 6th byte of `s` and a length value of 5. + +In other words, it looks like this: DIAGRAM GOES HERE of s, hello, and world -With Rust’s `..` syntax, if you want to start at zero, you can drop the zero. -In other words, these are equal: +With Rust’s `..` range syntax, if you want to start at the first index (zero), +you can drop the value before the `..`. In other words, these are equal: ```rust let s = String::from("hello"); @@ -902,8 +921,8 @@ let slice = &s[0..2]; let slice = &s[..2]; ``` -By the same token, if you want to go to the maximum value, which for slices is -the last element, you can drop the trailing number. In other words, these are +By the same token, if your slice should include the last byte of the +`String`, you can drop the trailing number. That means these are equal: ```rust @@ -911,8 +930,20 @@ let s = String::from("hello"); let len = s.len(); -let slice = &s[1..len]; -let slice = &s[1..]; +let slice = &s[3..len]; +let slice = &s[3..]; +``` + +You can also drop both values to take a slice of the entire string. So these +are equal: + +```rust +let s = String::from("hello"); + +let len = s.len(); + +let slice = &s[0..len]; +let slice = &s[..]; ``` With this in mind, let’s re-write `first_word()` to return a slice: @@ -921,8 +952,8 @@ With this in mind, let’s re-write `first_word()` to return a slice: fn first_word(s: &String) -> &str { let bytes = s.as_bytes(); - for (i, &byte) in bytes.iter().enumerate() { - if byte == 32 { + for (i, &item) in bytes.iter().enumerate() { + if item == 32 { return &s[0..i]; } } @@ -931,31 +962,22 @@ fn first_word(s: &String) -> &str { } ``` -Now, we have a single value, the `&str`. It contains both elements that we care -about: a reference to the starting point, and the number of elements. +Now we have a single value, the `&str`, pronounced "string slice". It stores +both elements that we care about: a reference to the starting point of the +slice and the number of elements in the slice. + This would also work for a `second_word()`: ```rust,ignore fn second_word(s: &String) -> &str { ``` -Same deal. We now have a straightforward API, that’s much harder to mess up. +We now have a straightforward API that’s much harder to mess up. But what about our error condition from before? Slices also fix that. Using the slice version of `first_word()` will throw an error: ```rust,ignore -# fn first_word(s: &String) -> &str { -# let bytes = s.as_bytes(); -# -# for (i, &byte) in bytes.iter().enumerate() { -# if byte == 32 { -# return &s[0..i]; -# } -# } -# -# &s[..] -# } fn main() { let mut s = String::from("hello world"); @@ -967,7 +989,7 @@ fn main() { Here’s the error: -```text +```bash 17:6 error: cannot borrow `s` as mutable because it is also borrowed as immutable [E0502] s.clear(); // Error! @@ -1003,7 +1025,7 @@ The type of `s` here is `&str`: It’s a slice, pointing to that specific point of the binary. This is also why string literals are immutable; `&str` is an immutable reference. -## String slices as arguments +### String slices as arguments Knowing that you can take slices of both literals and `String`s leads us to one more improvement on `first_word()`, and that’s its signature: @@ -1027,27 +1049,33 @@ with no loss of functionality: ```rust # fn first_word(s: &str) -> &str { # let bytes = s.as_bytes(); -# -# for (i, &byte) in bytes.iter().enumerate() { -# if byte == 32 { +# +# for (i, &item) in bytes.iter().enumerate() { +# if item == 32 { # return &s[0..i]; # } # } -# +# # &s[..] # } fn main() { - let s = String::from("hello world"); - let word = first_word(&s[..]); + let my_string = String::from("hello world"); + + // first_word works on slices of `String`s + let word = first_word(&my_string[..]); + + let my_string_literal = "hello world"; - let s = "hello world"; - let word = first_word(&s[..]); + // first_word works on slices of string literals + let word = first_word(&my_string_literal[..]); - let word = first_word(s); // since literals are &strs, this works too! + // since string literals *are* string slices already, + // this works too, without the slice syntax! + let word = first_word(my_string_literal); } ``` -# Other slices +## Other slices String slices, as you might imagine, are specific to strings. But there’s a more general slice type, too. Consider arrays: @@ -1066,6 +1094,6 @@ let slice = &a[1..3]; ``` This slice has the type `&[i32]`. It works the exact same way as string slices -do, with a reference to the first element, and a length. You’ll use this kind -of slice for all sorts of other collections. We’ll discuss these other slices -in detail when we talk about vectors, in Chapter 9.1. +do, by storing a reference to the first element and a length. You’ll use this +kind of slice for all sorts of other collections. We’ll discuss these in detail +when we talk about vectors in Chapter XX. diff --git a/nostarch/chapter05.md b/nostarch/chapter05.md new file mode 100644 index 0000000000..23ca0a003a --- /dev/null +++ b/nostarch/chapter05.md @@ -0,0 +1,486 @@ +# Structs + +A `struct`, short for "structure", gives us the ability to name and package +together multiple related values that make up a meaningful group. If you come +from an object-oriented language, a `struct` is like an object's data +attributes. `struct` and `enum` (that we talked about in the last chapter) are +the building blocks you can use in Rust to create new types in your program's +domain in order to take full advantage of Rust's compile-time type checking. + +Let’s write a program which calculates the distance between two points. +We’ll start off with single variable bindings, and then refactor it to +use `struct`s instead. + +Let’s make a new project with Cargo: + +```bash +$ cargo new --bin points +$ cd points +``` + +Here’s a short program which calculates the distance between two points. Put +it into your `src/main.rs`: + +```rust +fn main() { + let x1 = 0.0; + let y1 = 5.0; + + let x2 = 12.0; + let y2 = 0.0; + + let answer = distance(x1, y1, x2, y2); + + println!("Point 1: ({}, {})", x1, y1); + println!("Point 2: ({}, {})", x2, y2); + println!("Distance: {}", answer); +} + +fn distance(x1: f64, y1: f64, x2: f64, y2: f64) -> f64 { + let x_squared = f64::powi(x2 - x1, 2); + let y_squared = f64::powi(y2 - y1, 2); + + f64::sqrt(x_squared + y_squared) +} +``` + +Let's try running this program with `cargo run`: + +```bash +$ cargo run + Compiling points v0.1.0 (file:///projects/points) + Running `target/debug/points` +Point 1: (0, 5) +Point 2: (12, 0) +Distance: 13 +``` + +Let's take a quick look at `distance()` before we move forward. To find the +distance between two points, we can use the Pythagorean Theorem. The theorem is +named after Pythagoras, who was the first person to mathematically prove this +formula. The details aren't that important; just know the theorem says that the +formula for the distance between two points is equal to: + +- squaring the distance between the points horizontally (the "x" direction) +- squaring the distance between the points vertically (the "y" direction) +- adding those together +- and taking the square root of that. + +So that's what we're implementing here. + +```rust,ignore +f64::powi(2.0, 3) +``` + +The double colon (`::`) here is a namespace operator. We haven’t talked about +modules and namespaces in depth yet, but you can think of the `powi()` function +as being scoped inside of another name. In this case, the name is `f64`, the +same as the type. The `powi()` function takes two arguments: the first is a +number, and the second is the power that it raises that number to. In this +case, the second number is an integer, hence the ‘i’ in its name. Similarly, +`sqrt()` is a function under the `f64` module, which takes the square root of +its argument. + +## Why `struct`s? + +Our little program is okay, but we can do better. The key to seeing this is in +the signature of `distance()`: + +```rust,ignore +fn distance(x1: f64, y1: f64, x2: f64, y2: f64) -> f64 { +``` + +The distance function is supposed to calculate the distance between two points. +But our distance function calculates some distance between four numbers. The +first two and last two arguments are related, but that’s not expressed anywhere +in our program itself. It would be nicer if we had a way to group `(x1, y1)` +and `(x2, y2)` together. + +We’ve already discussed one way to do that: tuples. Here’s a version of our +program which uses tuples: + +```rust +fn main() { + let p1 = (0.0, 5.0); + + let p2 = (12.0, 0.0); + + let answer = distance(p1, p2); + + println!("Point 1: {:?}", p1); + println!("Point 2: {:?}", p2); + println!("Distance: {}", answer); +} + +fn distance(p1: (f64, f64), p2: (f64, f64)) -> f64 { + let x_squared = f64::powi(p2.0 - p1.0, 2); + let y_squared = f64::powi(p2.1 - p1.1, 2); + + f64::sqrt(x_squared + y_squared) +} +``` + +This is a little better, for sure. Tuples let us add a little bit of structure. +We’re now passing two arguments, so that’s more clear. But it’s also worse: +tuples don’t give names to their elements, so our calculation has gotten more +confusing: + +```rust,ignore +p2.0 - p1.0 +p2.1 - p1.1 +``` + +When writing this example, your authors almost got it wrong themselves! Distance +is all about `x` and `y` points, but our code is talking about `0` and `1`. +This isn’t great. + +Enter `struct`s. We can transform our tuples into something with a name for the +whole as well as names for the parts: + +```rust,ignore +let p1 = (0.0, 5.0); + +struct Point { + x: f64, + y: f64, +} + +let p1 = Point { x: 0.0, y: 5.0 }; +``` + +Here we've defined a `struct` and given it the name `Point`. The parts inside +`{}` are defining the _fields_ of the struct. We can have as many or as few of +them as we'd like, and we give them a name and specify their type. Here we have +two fields named `x` and `y`, and they both hold `f64`s. + +We can access the field of a struct in the same way we access an element of +a tuple, except we use its name: + +```rust,ignore +let p1 = (0.0, 5.0); +let x = p1.0; + +struct Point { + x: f64, + y: f64, +} + +let p1 = Point { x: 0.0, y: 5.0 }; +let x = p1.x; +``` + +Let’s convert our program to use our `Point` `struct`. Here’s what it looks +like now: + +```rust +#[derive(Debug,Copy,Clone)] +struct Point { + x: f64, + y: f64, +} + +fn main() { + let p1 = Point { x: 0.0, y: 5.0}; + + let p2 = Point { x: 12.0, y: 0.0}; + + let answer = distance(p1, p2); + + println!("Point 1: {:?}", p1); + println!("Point 2: {:?}", p2); + println!("Distance: {}", answer); +} + +fn distance(p1: Point, p2: Point) -> f64 { + let x_squared = f64::powi(p2.x - p1.x, 2); + let y_squared = f64::powi(p2.y - p1.y, 2); + + f64::sqrt(x_squared + y_squared) +} +``` + +Our function signature for `distance()` now says exactly what we mean: it +calculates the distance between two `Point`s. And rather than `0` and `1`, +we’ve got back our `x` and `y`. This is a win for clarity. + +## Derived Traits + +There’s one other thing that’s a bit strange here, this stuff above the +`struct` declaration: + +```rust,ignore +#[derive(Debug,Copy,Clone)] +struct Point { +``` + +This is an annotation that tells the compiler our struct should get some +default behavior for the `Debug`, `Copy`, and `Clone` traits. We talked about +marking that types can be `Copy` and `Clone`-able in Chapter XX when we +discussed ownership. `Debug` is the trait that enables us to print out our +struct so that we can see its value while we are debugging our code. + +So far, we’ve been printing values using `{}` in a `println!` macro. If we try +that with a struct, however, by default, we'll get an error. Say we have the +following program: + +```rust,ignore +struct Point { + x: f64, + y: f64, +} + +fn main() { + let p1 = Point { x: 0.0, y: 5.0}; + println!("Point 1: {}", p1); +} +``` + +This code tries to print the `p1` point directly, which may seem innocuous. But +running it produces the following output: + +```bash +$ cargo run + Compiling points v0.1.0 (file:///projects/points) +error: the trait bound `Point: std::fmt::Display` is not satisfied [--explain E0277] + --> src/main.rs:8:29 +8 |> println!("Point 1: {}", p1); + |> ^^ +:2:27: 2:58: note: in this expansion of format_args! +:3:1: 3:54: note: in this expansion of print! (defined in ) +src/main.rs:8:5: 8:33: note: in this expansion of println! (defined in ) +note: `Point` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string +note: required by `std::fmt::Display::fmt` +``` + +Whew! The core of the error is this part: *the trait bound `Point: +std::fmt::Display` is not satisfied*. `println!` can do many kinds of +formatting. By default, `{}` implements a kind of formatting known as +`Display`: output intended for direct end-user consumption. The primitive types +we’ve seen implement `Display`, as there’s only one way you’d show a `1` to a +user. But with structs, the output is less clear. Do you want commas or not? +What about the `{}`s? Should all the fields be shown? + +More complex types in the standard library and that are defined by the +programmer do not automatically implement `Display` formatting. Standard +library types implement `Debug` formatting, which is intended for the +programmer to see. The `#[derive(Debug)]` annotation lets us use a default +implementation of `Debug` formatting to easily get this ability for types we've +defined. To ask `println!` to use `Debug` formatting with our `Point`, we add +the annotation to derive the trait and include `:?` in the print string, like +this: + +```rust +#[derive(Debug)] +struct Point { + x: f64, + y: f64, +} + +fn main() { + let p1 = Point { x: 0.0, y: 5.0}; + println!("Point 1: {:?}", p1); +} +``` + +If you run this, it should print the values of each field in the `Point` struct +as desired: + +```bash +$ cargo run + Compiling points v0.1.0 (file:///projects/points) + Running `target/debug/points` +Point 1: Point { x: 0, y: 5 } +``` + +You’ll see this repeated later with other types. We’ll cover traits fully in +Chapter XX. + +## Method Syntax + +In the last section on ownership, we made several references to ‘methods’. +Methods look like this: + +```rust +let s1 = "hello"; + +// call a method on s1 +let s2 = s1.clone(); + +println!("{}", s1); +``` + +The call to `clone()` is attached to `s1` with a dot. This is called ‘method +syntax’, and it’s a way to call certain functions with a different style. + +Why have two ways to call functions? We’ll talk about some deeper reasons +related to ownership in a moment, but one big reason is that methods look nicer +when chained together: + +```rust,ignore +// with functions +h(g(f(x))); + +// with methods +x.f().g().h(); +``` + +The nested-functions version reads in reverse: the program executes `f()`, then +`g()`, then `h()`, but we read it left-to-right as `h()`, then `g()`, then +`f()`. The method syntax is executed in the same order as we would read it. + +Before we get into the details, let’s talk about how to define your own +methods. + +### Defining methods + +We can define methods with the `impl` keyword. `impl` is short for +‘implementation’. Doing so looks like this: + +```rust +#[derive(Debug,Copy,Clone)] +struct Point { + x: f64, + y: f64, +} + +impl Point { + fn distance(&self, other: &Point) -> f64 { + let x_squared = f64::powi(other.x - self.x, 2); + let y_squared = f64::powi(other.y - self.y, 2); + + f64::sqrt(x_squared + y_squared) + } +} + +let p1 = Point { x: 0.0, y: 0.0 }; +let p2 = Point { x: 5.0, y: 6.5 }; + +assert_eq!(8.200609733428363, p1.distance(&p2)); +``` + +Let’s break this down. First, we have our `Point` struct from earlier in the +chapter. Next comes our first use of the `impl` keyword: + +```rust,ignore +impl Point { + // ... +} +``` + +Everything we put inside of the curly braces will be methods implemented on +`Point`. Next is our definition: + +```rust,ignore +fn distance(&self, other: &Point) -> f64 { + // ... +} +``` + +Other than this, the rest of the example is familiar: an implementation of +`distance()` and using the method to find an answer. + +Our definition of `distance()` here as a method looks very similar to our +previous definition of `distance()` as a function, but with two differences. +Here's the `distance()` function again: + +```rust,ignore +fn distance(p1: Point, p2: Point) -> f64 { + // ... +} +``` + +The first difference is in the first argument. Instead of a name and a type, we +have written `&self`. This is what distinguishes a method from a function: +using `self` inside of an `impl` block means we have a method. Because we +already know that we are implementing this method on `Point` because of the +surrounding `impl Point` block, we don’t need to write the type of `self` out. + +Note that we have written `&self`, not just `self`. This is because we want to +take a reference to our argument's value rather than taking ownership of it. In +other words, these two forms are the same: + +```rust,ignore +fn foo(self: &Point) +fn foo(&self) +``` + +Just like any other parameter, you can take `self` in three forms. Here’s the +list, with the most common form first: + +```rust,ignore +fn foo(&self) // take self by reference +fn foo(&mut self) // take self by mutable reference +fn foo(self) // take self by ownership +``` + +In this case, we only need a reference. We don’t need to mutate either `Point` +to get the distance between them, so we won't take a mutable reference to the +`Point` that we call the method on. Methods that take ownership of `self` are +rarely used. An example of a time to do that would be if we wanted to have a +method that would transform `self` into something else and prevent other code +from using the value of `self` after the transformation happens. + +#### Methods and automatic referencing + +We’ve left out an important detail. It’s in this line of the example: + +```rust,ignore +assert_eq!(8.200609733428363, p1.distance(&p2)); +``` + +When we defined `distance()`, we took both `self` and the other argument by +reference. Yet, we needed a `&` for `p2` but not `p1`. What gives? + +This feature is called ‘automatic referencing’, and calling methods is one +of the few places in Rust that has behavior like this. Here’s how it works: +when you call a method with `self.(`, Rust will automatically add in `&`s +or `&mut`s to match the signature. In other words, these are the same: + +```rust +# #[derive(Debug,Copy,Clone)] +# struct Point { +# x: f64, +# y: f64, +# } +# +# impl Point { +# fn distance(&self, other: &Point) -> f64 { +# let x_squared = f64::powi(other.x - self.x, 2); +# let y_squared = f64::powi(other.y - self.y, 2); +# +# f64::sqrt(x_squared + y_squared) +# } +# } +# let p1 = Point { x: 0.0, y: 0.0 }; +# let p2 = Point { x: 5.0, y: 6.5 }; +p1.distance(&p2); +(&p1).distance(&p2); +``` + +The first one looks much, much cleaner. Here’s another example: + +```rust +let mut s = String::from("Hello,"); + +s.push_str(" world!"); + +// The above is the same as: +// (&mut s).push_str(" world!"); + +assert_eq!("Hello, world!", s); +``` + +Because [`push_str()`] has the following signature: + +```rust,ignore +fn push_str(&mut self, string: &str) { +``` + +[`push_str()`]: http://doc.rust-lang.org/collections/string/struct.String.html#method.push_str + +This automatic referencing behavior works because methods have a clear receiver +— the type of `self` — and in most cases it’s clear given the receiver and name +of a method whether the method is just reading (so needs `&self`), mutating (so +`&mut self`), or consuming (so `self`). The fact that Rust makes borrowing +implicit for method receivers is a big part of making ownership ergonomic in +practice. diff --git a/nostarch/chapter06.md b/nostarch/chapter06.md new file mode 100644 index 0000000000..57d5ba53d6 --- /dev/null +++ b/nostarch/chapter06.md @@ -0,0 +1,601 @@ +# Enums + +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 definition: + +```rust +enum IpAddrKind { + V4, + V6, +} +``` + +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. + +We can create values of `IpAddrKind` like this: + +```rust +# enum IpAddrKind { +# V4, +# V6, +# } +# +let four = IpAddrKind::V4; +let six = IpAddrKind::V6; +``` + +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; +we only know what kind it is. Given that you just learned about structs, you +might tackle this problem like this: + +```rust +enum IpAddrKind { + V4, + V6, +} + +struct IpAddr { + kind: IpAddrKind, + address: String, +} + +let home = IpAddr { + kind: IpAddrKind::V4, + address: String::from("127.0.0.1"), +}; + +let loopback = IpAddr { + kind: IpAddrKind::V6, + address: String::from("::1"), +}; +``` + +We’ve used a struct to bundle the two values together: now we keep the kind +with the value itself. We can represent the same thing in a different way with +just an enum: + +```rust +enum IpAddr { + V4(String), + V6(String), +} + +let home = IpAddr::V4(String::from("127.0.0.1")); + +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 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: + +```rust +enum IpAddr { + V4(u8, u8, u8, u8), + V6(String), +} + +let home = IpAddr::V4(127, 0, 0, 1); + +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: + +```rust +struct Ipv4Addr { + // details elided +} + +struct Ipv6Addr { + // details elided +} + +enum IpAddr { + V4(Ipv4Addr), + V6(Ipv6Addr), +} +``` + +[IpAddr]: http://doc.rust-lang.org/std/net/enum.IpAddr.html + +Here’s an enum with a variety of types embedded in its variants: + +```rust +enum Message { + Quit, + Move { x: i32, y: i32 }, + Write(String), + ChangeColor(i32, i32, i32), +} +``` + +* `Quit` has no data associated with it at all. +* `Move` includes an anonymous struct inside of it. +* `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`. + +## Option + +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 +that is in many other languages: 'null'. In languages with this feature, +variables can have two states: null or not-null. + +The inventor of this concept has this to say: + +> I call it my billion-dollar mistake. At that time, I was designing the first +> comprehensive type system for references in an object-oriented language. My +> goal was to ensure that all use of references should be absolutely safe, with +> checking performed automatically by the compiler. But I couldn't resist the +> temptation to put in a null reference, simply because it was so easy to +> implement. This has led to innumerable errors, vulnerabilities, and system +> crashes, which have probably caused a billion dollars of pain and damage in +> the last forty years. +> +> - Tony Hoare "Null References: The Billion Dollar Mistake" + +The problem with null values is twofold: first, a value can be null or not, at +any time. The second is that if you try to use a value that's null, you'll get +an error of some kind, depending on the language. Because this property is +pervasive, it's extremely easy to make this kind of error. + +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 +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 { + Some(T), + None, +} +``` + +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::`. + +[option]: ../std/option/enum.Option.html + +Here's an example of using `Option`: + +```rust +let some_number = Some(5); +let some_string = Some("a string"); + +// If we only say None, we need to tell Rust what type of Option we have. +let absent_number: Option = None; +``` + +Let's dig in. First, you'll notice that we used the `` syntax when defining +`Option`: it's a generic enum. `Option` has two variants: `Some`, which +contains a `T`, and `None`, which has no data associated with it. In some +sense, `None` means 'null', and `Some` means 'not null'. So why is this any +better than null? + +In short, because `Option` and `T` are different types. That's a bit too +short though. Here's an example: + +```rust,ignore +let x: i8 = 5; +let y: Option = Some(5); + +let sum = x + y; +``` + +This will not compile. We get an error message like this: + +```text +error: the trait bound `i8: std::ops::Add>` is not +satisfied [E0277] + +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`: 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. + +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. + +[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? And more generally, how do we get +the inner values out of any enum variant? We need a new feature: `match`. + +## 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. + +Think of a `match` expression 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. In the same way, values +go through each pattern in a `match`, and for the first pattern that the value +"fits", the value will fall into the associated code block to be used during +execution. + +Since we're already talking about coins, let's use them for an example using +`match`! We can write a function 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 { + Penny, + Nickel, + Dime, + Quarter, +} + +fn value_in_cents(coin: Coin) -> i32 { + match coin { + Coin::Penny => 1, + Coin::Nickel => 5, + Coin::Dime => 10, + 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 { +# Penny, +# Nickel, +# Dime, +# Quarter, +# } +# +fn value_in_cents(coin: Coin) -> i32 { + match coin { + Coin::Penny => { + println!("Lucky penny!"); + 1 + }, + Coin::Nickel => 5, + Coin::Dime => 10, + 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 { + Penny, + Nickel, + Dime, + 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 { +# Penny, +# Nickel, +# Dime, +# Quarter(UsState), +# } +# +fn value_in_cents(coin: Coin) -> i32 { + match coin { + Coin::Penny => 1, + Coin::Nickel => 5, + Coin::Dime => 10, + 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: + +```text +None => None, +``` + +Does `Some(5)` match `None`? No, it's the wrong variant. So let's continue. + +```text +Some(i) => Some(i + 1), +``` + +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: + +```text +None => None, +``` + +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, 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. + +### Matches are exhaustive + +There's one other aspect of `match` we didn't talk about. Consider this version +of `plus_one()`: + +```rust,ignore +fn plus_one(x: Option) -> Option { + match x { + Some(i) => Some(i + 1), + } +} +``` + +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] +match x { + Some(i) => Some(i + 1), +} +``` + +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. 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 + +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 { + 1 => println!("one"), + 3 => println!("three"), + 5 => println!("five"), + 7 => println!("seven"), + _ => (), +} +``` + +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 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. + +## if let + +There's one more advanced control flow structure we haven't discussed: `if +let`. Imagine we're in a situation like this: + +```rust +# let some_option = Some(5); +match some_option { + Some(x) => { + // do something with x + }, + None => {}, +} +``` + +We care about the `Some` case, but don't want to do anything with the `None` +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 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 +others." + +Enter `if let`: + +```rust +# let some_option = Some(5); +if let Some(x) = some_option { + // do something with x +} +``` + +`if let` takes a pattern and an expression, separated by an `=`. It works +exactly like a `match`, where the expression is given to the `match` and the +pattern is its first arm. In other words, you can think of `if let` as syntax +sugar: + +```rust,ignore +if let pattern = expression { + body +} + +match expression { + pattern => body, + _ => {} +} +``` + +And in fact, we can include an `else` and it becomes the body of the `_` +case: + +```rust,ignore +if let pattern = expression { + body +} else { + else_body +} + +match expression { + pattern => body, + _ => else_body, +} +``` + +In other words, it's the high-level construct we were originally looking for: +do something special with only one pattern. diff --git a/nostarch/chapter3.md b/nostarch/chapter3.md deleted file mode 100644 index 19581d40b3..0000000000 --- a/nostarch/chapter3.md +++ /dev/null @@ -1,2332 +0,0 @@ - - - - - - - - - -[TOC] - -# Up and Running - -We’ll start our Rust journey by talking about the absolute basics, concepts that appear in almost every programming language. Many programming languages have much in common at their core. None of the concepts presented in this chapter are unique to Rust, but we’ll discuss Rust’s particular syntax and conventions concerning these common concepts. - - - - - - - - -Specifically, we’ll be talking about variable bindings, functions, basic types, comments, `if` statements, and looping. These foundations will be in every Rust program, and learning them early will give you a strong core to start from. - - -## Anatomy of a Rust Program - - - -The foundation of virtually every program is the ability to store and modify data, but to create this data, you first have to create a program. Here, we'll write some code that demonstrates how to begin a Rust program, how to bind a variable, and how to print text to the terminal. - - - - - -#### A Simple Program that Binds a Variable - - - - -Let’s start with a short example that binds a value to a variable, and then uses that binding in a sentence that we'll print to the screen. First, we’ll generate a new project with Cargo. Open a terminal, and navigate to the directory you want to store your projects in. From there, generate a new project: - -```bash -$ cargo new --bin bindings -$ cd bindings -``` - - - - -This creates a new project called `bindings` and sets up our *Cargo.toml* and *src/main.rs* files. As we saw in Chapter XX, Cargo will generate these files and create a little "hello world" program like this: - -```rust -fn main() { - println!("Hello, world!"); -} -``` - -Open that program and replace its code with the following: - -```rust -fn main() { - let x = 5; - - println!("The value of x is: {}", x); -} -``` - -This is the full program for our example. Enter the `run` command now to to see it working: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -``` - - - - -If you get an error instead of this output, double check that you've copied the program -exactly as written, and then try again. Now let’s break this program down, line by line. - -#### Starting a Program with the main() Function - -Most Rust programs open with the same first line as this one from our example program: - -```rust,ignore -fn main() { -``` - -The `main()` function is the entry point of every Rust program. It doesn’t have to be at the very beginning of our source code, but it will be the first bit of code that runs when we execute our program. We’ll talk more about functions in the next section, but for now, just know is that ```main()``` is where our program begins. The opening curly brace (`{`) indicates the start of the function’s body. - - - - - -#### Binding a Variable with `let` - -Inside the function body, we added the following: - -```rust,ignore - let x = 5; -``` - -This is a `let` statement, and it binds the value `5` to the variable `x`. Basic `let` statements take the following form: - -```text -let NAME = EXPRESSION; -``` - - - - - - -A `let` statement first evaluates the `EXPRESSION`, and then binds the resulting value to `NAME` to give us a variable to use later in the program. Notice the semicolon at the end of the statement, too. As in many other programming languages, statements in Rust must end with a semicolon. - -In this simple example, the expression already is a value, but we could achieve the same result like this: - -```rust -let x = 2 + 3; -``` - - - -The expression `2 + 3` would evaluate to `5`, which would in turn be stored in the `x` variable binding. In general, `let` statements work with *patterns*. Patterns are part of a feature of Rust called ‘pattern matching’. We can compare an expression against a pattern, and then make a choice based on how the two compare. A name like `x` is a particularly humble form of pattern; it will always match. Patterns are a big part of Rust, and we’ll see more complex and powerful patterns as we go along. - - - - -#### Printing to the Screen with a Macro - -The next line of our program is: - -```rust,ignore - println!("The value of x is: {}", x); -``` - - - - -The `println!` command is a *macro* that prints the text passed to it to the screen. Macros are indicated with the `!` character. In Chapter , you'll learn how to write macros your, but for now we'll use macros provided by the standard Rust library. Macros can add new syntax to the language, and the `!` is a reminder that things may look slightly unusual. - - - - -The `println!` macro only requires one argument: a format string. You can add optional arguments inside this format string by using the special text `{}`. Each instance of `{}` corresponds to an additional argument. Here’s an example: - -```rust -let x = 2 + 3; -let y = x + 5; - -println!("The value of x is {}, and the value of y is {}", x, y); -``` - -If you were to run a program containing these statements, it would print the following: - -```rust -The value of x is 5, and the value of y is 10 -``` - -Think of `{}` as little crab pincers, holding a value in place. The first `{}` holds the first value after the format string, the second set holds the second value, and so on. - - - - - - -The `{}` placeholder has a number of more advanced formatting options that we’ll discuss -later. - -After the `println` macro, we match the opening curly brace that declared the `main()` function with a closing curly brace to declare the end of the function: - -```rust,ignore -} -``` - -And of course, when we run the program, our output is: - -```text - -The value of x is: 5 - -``` - - - - -With this simple program, you've created your first variable and used your first Rust macro. That makes you a Rust programmer. Welcome! Now that you've seen the basics, let's explore variable bindings further. - -## Variable Bindings in Detail - - - -So far, we’ve created the simplest kind of variable binding, but the `let` statement has some tricks up its sleeve. -Let’s do some more complex things: create multiple bindings at once, how to add type annotations, mutating bindings, -shadowing, and more. - -### Creating Multiple Bindings - -The previous example program just bound one variable, but it's also possible to create multiple variable bindings in one go. Let’s try a more complex example, creating two variable bindings at once. Change your example program to this: - -```rust -fn main() { - let (x, y) = (5, 6); - - println!("The value of x is: {}", x); - println!("The value of y is: {}", y); -} -``` - -And enter `cargo run` to run it: - -```text -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -The value of y is: 6 -``` - - - -We’ve created two bindings with one `let` statement! - - - - - - - -The `let` statement binds the values in `(5, 6)` to the corresponding patterns of `(x, y)`. The first value `5` binds to the first part of the pattern, `x`, and the second value `6` binds to `y`. We could alternatively have used two `let` statements to the same effect, as follows: - - -```rust -fn main() { - let x = 5; - let y = 6; -} -``` - -In simple cases like this, where we are only binding two variables, two `let` statements may be clearer in the code, but when you're creating many multiple bindings, it's useful to be able to do so all at once. Deciding which technique to use is mostly a judgement call, and as you become more proficient in Rust, you’ll be able to figure out which style is better in each case. - -### Delayed Initialization - -The examples so far have all provided bindings with an initial value, but that isn't always necessary. Rather, we can assign a value for the binding later, after the `let` statement. To try this out, write the following program: - -```rust -fn main() { - let x; - - x = 5; - - println!("The value of x is: {}", x); -} -``` - -And enter `cargo run` to run it: - -```text -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -``` - -As you can see, this works just like the previous program, in which we assigned an initial value. - -This raises an interesting question: what happens if we try to print out a binding before we declare a value? Let's find out. Modify your code to look like the following: - - - - - -```rust,ignore -fn main() { - let x; - - println!("The value of x is: {}", x); - - x = 5; -} -``` - -When you enter `cargo run` to run this code, you should see output like this after the command: - -```text - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x` [E0381] -src/main.rs:4 println!("The value of x is: {}", x); - ^ -:2:25: 2:56 note: in this expansion of format_args! -:3:1: 3:54 note: in this expansion of print! (defined in ) -src/main.rs:4:5: 4:42 note: in this expansion of println! (defined in ) -src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed explanation -error: aborting due to previous error -Could not compile `bindings`. - -To learn more, run the command again with --verbose. -``` - - - -There's been an error! The compiler won’t let us write a program like this, and instead it requests that you declare a value. This is our first example of the compiler helping us find an error in our program. Different programming languages have different ways of approaching this problem. Some languages will always initialize values with some sort of default. Other languages leave the value uninitialized, and make no promises about what happens if you try to use something before initialization. Rust responds with an error to prod the programmer to declare the value they want. We must initialize any variable before we can use it. - - - - - -### Extended Error Explanations - -Now that you've seen an example of a Rust error, I want to point out one particularly useful aspect of errors. Rust encourages you to seek further information on the kind of error you've received with output like this: - -```text -src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed explanation -``` - -This tells us that if we pass the `--explain` flag to `rustc` with the provided error code, we can see an extended explanation, which will try to explain common causes of and solutions to that kind of error. Not every error has a longer explanation, but many do. Here’s the explanation for the `E0381` error we received previously: - -```bash -$ rustc --explain E0381 -It is not allowed to use or capture an uninitialized variable. For example: - -fn main() { - let x: i32; - - let y = x; // error, use of possibly uninitialized variable - -To fix this, ensure that any declared variables are initialized before being -used. -``` - -These explanations can really help if you’re stuck on an error, so don't hesitate to look up the error code. The compiler is your friend, and it's there to help. - -### Mutable bindings - -By default, variable bindings are *immutable*, meaning that once a value is bound, you can't change that value. Try writing the following sample program to illustrate this: - -```rust,ignore -fn main() { - let x = 5; - - x = 6; - - println!("The value of x is: {}", x); -} -``` - -Save and run the program, and you should receive another error message, as in this output: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:4:5: 4:10 error: re-assignment of immutable variable `x` [E0384] -src/main.rs:4 x = 6; - ^~~~~ -src/main.rs:4:5: 4:10 help: run `rustc --explain E0384` to see a detailed explanation -src/main.rs:2:9: 2:10 note: prior assignment occurs here -src/main.rs:2 let x = 5; - ^ -``` - -The error includes the message `re-assigment of immutable variable` because the program tried to assign a second value to the `x` variable. But bindings are immutable only by default; you can make them mutable by adding `mut` in front of the variable name. For example, change the program you just wrote to the following: - -```rust -fn main() { - let mut x = 5; - - println!("The value of x is: {}", x); - - x = 6; - - println!("The value of x is: {}", x); -} -``` - -Running this, we get: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 5 -The value of x is: 6 -``` - -Using `mut`, we change the value that `x` binds to from `5` to `6`. Note, however, that `mut` is part of the pattern in the `let` statement. This becomes more obvious if we add mutability to a pattern that binds multiple variables, like this: - -```rust,ignore -fn main() { - let (mut x, y) = (5, 6); - - x = 7; - y = 8; -} -``` - -If you run this code, the compiler will output an error: - -```bash -$ cargo build - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:5:5: 5:10 error: re-assignment of immutable variable `y` [E0384] -src/main.rs:5 y = 8; - ^~~~~ -src/main.rs:5:5: 5:10 help: run `rustc --explain E0384` to see a detailed explanation -src/main.rs:2:17: 2:18 note: prior assignment occurs here -src/main.rs:2 let (mut x, y) = (5, 6); - ^ -``` - -The way `mut` is used here, the compiler is fine with reassigning the `x` variable, but not the `y` variable. That's because `mut` only applies to the name that directly follows it, not the whole pattern. For the compiler to allow you to reassign the `y` variable, you'd need to write the pattern as `(mut x, mut y)` instead. - - - - - - - -One thing to know about mutating bindings: `mut` allows you to mutate _the binding_, but not _what the name binds to_. In other words, the value is not what changes, but rather the path between the value and the name. For example: - - - - - -```rust -fn main() { - let mut x = 5; - - x = 6; -} -``` - -This does not change the value that `x` is bound to, but creates a new value (`6`) and changes the binding so that it binds the name `x` to this new value instead. This subtle but important difference will become more important as your Rust programs get more complex. - - - - - - -### Variable Binding Scope - - - - -Another important thing to know about variable bindings is that they are only valid as long as they are *in scope*. That scope begins at the point where the binding is declared, and ends at with the curley brace that closes the block of code containing it. We cannot access bindings "before they come into scope" or "after they go out of scope." Here’s an example to illustrate this: - - -```rust -fn main() { - println!("x is not yet in scope"); - - let x = 5; - - println!("x is now in scope"); - - println!("In real code, we’d now do a bunch of work."); - - println!("x will go out of scope now! The next curly brace is ending the main function."); -} -``` - -The variable binding for `x` goes out of scope with the last curly brace in the `main()` function. - - - - -This example only has one scope, though. In Rust, it's possible to create arbitrary scopes within a scope by placing code within another pair of curly braces. For example: - - - - -```rust - -fn main() { - - println!("x is not yet in scope"); - - let x = 5; - - println!("x is now in scope"); - - println!("Let’s start a new scope!"); - - { - let y = 5; - - println!("y is now in scope"); - println!("x is also still in scope"); - - println!("y will go out of scope now!"); - println!("The next curly brace is ending the scope we started."); - } - - println!("x is still in scope, but y is now out of scope and is not usable"); - - println!("x will go out of scope now! The next curly brace is ending the main function."); -} - -``` - - - - -The `y` variable is only in scope in the section of the code that's between the nested pair of curly braces, whereas `x` is in scope from the `let` statement that binds it until the final curly brace. The scope of bindings will become much more important later, as you learn about references in Chapter XX. - -### Shadowing Earlier Bindings - - - -One final thing about bindings: they can *shadow* previous bindings with the same name. Shadowing is what happens when you declare two bindings with the same name, we say that the second binding ‘shadows’ the first. - - - - -This can be useful if you’d like to perform a few transformations on a value, but still leave the binding immutable. For example: - -```rust -fn main() { - let x = 5; - - let x = x + 1; - - let x = x * 2; - - println!("The value of x is: {}", x); -} -``` - - - -This program first binds `x` to a value of `5`. Then, it shadows `x`, taking the original value and adding `1` so that the value of `x` is then `6`. The third `let` statement shadows `x` again, taking the previous value and multiplying it by `2` to give `x` a final value of `12`. If you run this, it will output: - - - - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -The value of x is: 12 -``` - -Shadowing is useful because it lets us modify `x` without having to make the variable mutable. This means the compiler will still warn us if we accidentally try to mutate `x` directly later. For example, say after calculating `12` we don’t want `x` to be modified again; if we write the program in a mutable style, like this: - - - -```rust -fn main() { - let mut x = 5; - - x = x + 1; - x = x * 2; - - println!("The value of x is: {}", x); - - x = 15; - - println!("The value of x is: {}", x); -} -``` - -Rust is happy to let us mutate `x` again, to `15`. A similar program using the default immutable style, however, will let us know about that accidental mutation. Here's an example: - -```rust,ignore -fn main() { - let x = 5; - let x = x + 1; - let x = x * 2; - - println!("The value of x is: {}", x); - - x = 15; - - println!("The value of x is: {}", x); -} -``` - -If we try to compile this, we get an error: - -```bash -$ cargo build - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:8:5: 8:11 error: re-assignment of immutable variable `x` [E0384] -src/main.rs:8 x = 15; - ^~~~~~ -src/main.rs:8:5: 8:11 help: run `rustc --explain E0384` to see a detailed explanation -src/main.rs:4:9: 4:10 note: prior assignment occurs here -src/main.rs:4 let x = x * 2; - ^ -error: aborting due to previous error -Could not compile `bindings`. -``` - -Since we don't want the binding to be mutable, this exactly what should happen. - -#### Shadowing Over Bindings - - - -You can also shadow bindings over one another, without re-using the initial binding. Here's how that looks: - -```rust - -fn main() { - let x = 5; - let x = 6; - - println!("The value of x is: {}", x); -} -``` - -Running this sample program, we can see the shadowing in action: - -```text -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) -src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default -src/main.rs:2 let x = 5; - ^ - Running `target/debug/bindings` -The value of x is: 6 - -``` - -Rust gives the value of `x` as `6`, which is the value from the *second* `let` statement. There are a few interesting things in this output. First, that Rust will compile and run the program without issue. This is because we haven't mutated the value; instead, we declared a _new_ binding that is _also_ named `x`, and gave it a new value. - - - - -The other interesting thing in this output is this error line: - -```text -src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default -``` - -Rust is pointing out that we shadowed `x`, but never used the initial value. Doing so isn’t _wrong_, but Rust is checking whether this is intentional and not just a mistake. In this case, the compiler issues a warning, but still compiles our program. A warning like this is called a *lint*, which is an old term for the bits of fluff and fibers in sheep’s wool that you wouldn't want to put in cloth. - -Similarly, this lint is telling us that we may have an extra bit of code (the statement `let x = 5`) that we don’t need. Even though our program works just fine, listening to these warnings and fixing the problems they point out is worthwhile, as they can be signs of a larger problem. In this case, we may not have realized that we were shadowing `x`, when we meant to, say, define a new variable with a different name. - -Shadowing can take some time to get used to, but it’s very powerful, and works well with immutability. - -#### Shadowing and Scopes - -Like any binding, a binding that shadows another binding becomes invalid at the end of a scope. Here’s an example program to illustrate this: - -```rust -fn main() { - let x = 5; - - println!("Before shadowing, x is: {}", x); - - { - let x = 6; - - println!("Now that x is shadowed, x is: {}", x); - } - - println!("After shadowing, x is: {}", x); -} -``` - -This code first creates the `x` variable and prints `x` to the terminal. Then, inside a new scope, it creates a new binding for `x` with a new value, and prints that value. When the arbitrary scope ends, `x` is printed once more. If we run this example, we can see the shadow appear and disappear in the output: - -```bash -$ cargo run - Compiling bindings v0.1.0 (file:///projects/bindings) - Running `target/debug/bindings` -Before shadowing, x is: 5 -Now that x is shadowed, x is: 6 -After shadowing, x is: 5 -``` - -In this case, the binding value reverts to the original value once the shadow binding goes out of scope. - - - -## How Functions Work in Rust - - - - -Functions are pervasive in Rust code. We’ve already seen one of the most important functions in the language: the `main()` function that’s the start of every program. We've also seen the `fn` keyword, which allows us to declare new functions. - - - - - - - -Rust code uses *snake case* as the conventional style for function names. In snake case, all letters are lower case, and there are underscores separating words. (Rust also uses snake case for the names of variable bindings; we just haven't used any variable bindings long enough to need underscores yet.) Here's a program containing an example function definition: - -```rust -fn main() { - println!("Hello, world!"); - - another_function(); -} - -fn another_function() { - println!("Another function."); -} -``` - - - - -Function definitions in Rust always start with `fn` and have a set of parentheses after the function name. The curly braces tell the compiler where the function begins and ends. - -We can call any function we’ve defined by entering its name followed by a pair of parentheses. Since `another_function()` is defined in the program, it can be called from inside the `main()` function. Note that we defined `another_function()` _after_ the `main()` function in our source code; we could have defined it before as well. Rust doesn’t care where you define your functions, only that they are defined somewhere. - -Let’s start a new project to explore functions further. Open a terminal, and navigate to the directory you're keeping your projects in. From there, use Cargo to generate a new project, as follows: - -```bash -$ cargo new --bin functions -$ cd functions -``` - - - - - - -Place the `another_function()` example in a file named *src/main.rs* and run it. You should see the following output: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -Hello, world! -Another function. -``` - -The lines execute in the order they appear in the `main()` function. First, our “Hello, world!” message prints, and then `another_function()` is called and its message is printed. - -### Function Arguments - - - - - -Functions can also take arguments. The following rewritten version of `another_function()` shows what arguments look like in Rust: - - -```rust -fn main() { - another_function(5); -} - -fn another_function(x: i32) { - println!("The value of x is: {}", x); -} -``` - - - - -Try running this program, and you should get this output: - - - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of x is: 5 -``` - -Since `main()` passed `5` to `another_function()`, the `println` macro put `5` where the pair of curly braces were in the format string. - -Let’s take a closer look at the signature of a function which takes a single argument: - - - -```text -fn NAME(PATTERN: TYPE) { -``` - -The parameter declaration in a single-argument function signature looks like the `let` bindings we used earlier. Just look at both together, and compare them: - -```rust,ignore -let x: i32; -fn another_function(x: i32) { -``` - - - - -The one difference is that in function signatures, we _must_ declare the type. This is a deliberate decision in the design of Rust; requiring type annotations in function definitions means you almost never need to use them elsewhere in the code. - - - - -When you want a function to have multiple arguments, just separate them inside the function signature with commas, like this: - -```text -fn NAME(PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE...) { -``` - -And just like a `let` declaration with multiple patterns, a type must be applied to each pattern separately. To demonstrate, here’s a full example of a function with multiple arguments: - -```rust -fn main() { - another_function(5, 6); -} - -fn another_function(x: i32, y: i32) { - println!("The value of x is: {}", x); - println!("The value of y is: {}", y); -} -``` - - - - -In this example, we make a function with two arguments. In this case, both are `i32`s, but if your function has multiple arguments, they don’t have to be the same time. They just happen to be in this example. Our function then prints out the values of both of its arguments. - -Let’s try out this code. Replace the program currently in your `function` project's `main.rs` file with the example above, and run it as follows: - - - -```bash - -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of x is: 5 -The value of y is: 6 -``` - -Since `5` is passed as the `x` argument and `6` is passed as the `y` argument, the two strings are printed with these values. - -### Bindings as Arguments - - - - -It's also possible to create bindings and pass them in as arguments in Rust. For example: - -```rust -fn main() { - let a = 5; - let b = 6; - - another_function(a, b); -} - -fn another_function(x: i32, y: i32) { - println!("The value of x is: {}", x); - println!("The value of y is: {}", y); -} -``` - -Instead of passing `5` and `6` directly, this first creates two bindings containing the values, and passes those bindings instead. When you run this, you'll find that it has the same effect as just using integers: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of x is: 5 -The value of y is: 6 -``` - -Note that our bindings are called `a` and `b`, yet inside the function, we refer to them by the names in the signature, `x` and `y`. Inside a function, its parameters are in scope but the names of the bindings we passed as parameters are not, so we need to use the parameter names within the function block. Bindings passed as parameters don’t need to have the same names as the arguments. - -### Functions with Return Values - - - - -Functions can return values back to functions that call them. The signature for a function that returns a value looks like this: - -```TEXT -fn NAME(PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE, PATTERN: TYPE...) -> TYPE { -``` - -In Rust, we don’t name return values, but we do declare their type, after the arrow (`->`). Here’s a sample program to illustrate this concept: - -```rust -fn main() { - let x = five(); - - println!("The value of x is: {}", x); -} - -fn five() -> i32 { - 5 -} -``` - -There are no function calls, macros, or even `let` statements in the `five()` function--just the number `5` by itself. That's a perfectly valid function in Rust. Note the function's return type, too. Try running this code, and the output should look like this: - - - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of x is: 5 -``` - - - - - -The `5` in `five()` is actually the function's return value, which is why the return type is `i32`. Let’s examine this in more detail. There are two important bits. First, the line `let x = five();` in `main()` shows that we can use the return value of a function to initialize a binding. - - - -Because the function `five()` returns a `5`, that line is the same as saying: - -```rust -let x = 5; -``` - -The second interesting bit is the `five()` function itself. It requires no arguments and defines the type of the return, but the body of the function is a lonely `5` with no semicolon. So far, we’ve ended almost every line in our programs with a semicolon, so why not here? - - - -The answer is that the return value of a function is the value of its final expression. To explain this, we have to go over statements and expressions. - -### Statements and Expressions - - - - -Expressions are bits of code that evaluate to a value. Consider a simple math operation, like this: - -```rust,ignore -5 + 6 -``` - -Evaluating this expression results in the value: `11`. In Rust, most bits of code are expressions. For example, calling a function is an expression: - - - -```rust,ignore -foo(5) -``` - -The value is equal to the return value of the `foo()` function. - -Statements are instructions. While expressions _compute_ something, statements perform some action. For example, `let` statements bind variables, and `fn` declarations are statements that begin functions. - -One practical difference between an expression and a statement is that you can bind an expression, but you can't bind a statement. - - - - -For example, `let` is a statement, so you can’t assign it to another binding, as this code tries to do: - -```rust,ignore -fn main() { - let x = (let y = 6); -} -``` - -If we were to run this program, we’d get an error like this: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) -src/main.rs:2:14: 2:17 error: expected identifier, found keyword `let` -src/main.rs:2 let x = (let y = 6); - ^~~ -src/main.rs:2:18: 2:19 error: expected one of `!`, `)`, `,`, `.`, `::`, `{`, or an operator, found `y` -src/main.rs:2 let x = (let y = 6); - ^ -Could not compile `functions`. -``` - - - -In the same way, we can't assign a `fn` declaration to a binding, either. - -#### Expressions as Return Values - - - -So what does the way statements and expressions work have to do with return values? Well, the block that we use to create new scopes, `{}`, is an expression. Let’s take a closer look at `{}` with the following signature: - - - -```text -{ - STATEMENT* - EXPRESSION -} -``` - - - - -The `*` by `STATEMENT` indicates "zero or more," meaning we can have any number of statements inside a block, followed by an expression. Since blocks are expressions themselves, we can nest blocks inside of blocks. - - - - -And since blocks return a value, we can use them in `let` statements. For example: - -```rust -fn main() { - - let x = 5; - - let y = { - let z = 1; - - x + z + 5 - }; - - println!("The value of y is: {}", y); -} -``` - - - -Here, we're using a block to give us a value for the `y` variable. Inside that block, we create a new variable binding, `z`, with a `let` statement and give `z` a value. For the final expression of the block, we do some math, ultimately binding the result to `y`. Since `x` is `5` and `z` is `1`, the calculation is `5 + 1 + 5`, and so the value of the entire block is `11`. This gets substituted into our `let` statement for `y`, making that statement equivalent to: - -```rust,ignore -let y = 11; -``` - -Try running the program, and you should see the following output: - -```bash - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of y is: 11 -``` - - - - - - - - - -As expected, the output string says that `y` is `11`. - -#### Functions Are Expressions (Or a different heading, if this one doesn't make sense.) - - -We also use blocks as the body of functions, for example: - - - - - -```rust -fn main() { - let x = 5; - - let y = { - x + 1 - }; - - println!("The value of y is: {}", y); - - let y = plus_one(x); - - println!("The value of y is: {}", y); -} - -fn plus_one(x: i32) -> i32 { - x + 1 -} -``` - -In both `let` statements that bind values to the `y` variable, we use a block to produce the value. In the first case, the block is an arbitrary scope nested within the `main()` function. In the second, the block is the body of the `plus_one()` function, which is passed `x` as a parameter. Running this gives: - - - - - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of y is: 6 -The value of y is: 6 -``` - -The `x` variable doesn't change before the new `y` variable is created and bound to the return value of the `plus_one()` function, so both `println` macros tell us that `y` is `6`. - - - - - - - - - - -#### Expression Statements - -Another impoortant thing to know about expressions and statements is that adding a semicolon to the end of an expression turns it into a statement. For example, look at this modified version of our `plus_one()` function from earlier: - -```rust,ignore -fn main() { - let x = plus_one(5); - - println!("The value of x is: {}", x); -} - -fn plus_one(x: i32) -> i32 { - x + 1; -} - -``` - - - - -Since `x + 1` is the only code in the function, it should be an expression, so that the value it evaluates to can be the function's return value. But the semicolon has turned it into a statement, so running this code would give an error, as follows: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) -src/main.rs:7:1: 9:2 error: not all control paths return a value [E0269] -src/main.rs:7 fn plus_one(x: i32) -> i32 { -src/main.rs:8 x + 1; -src/main.rs:9 } -src/main.rs:7:1: 9:2 help: run `rustc --explain E0269` to see a detailed explanation -src/main.rs:8:10: 8:11 help: consider removing this semicolon: -src/main.rs:8 x + 1; - ^ -error: aborting due to previous error -Could not compile `functions`. -``` - -The main error message, "not all control paths return a value," reveals the core of the issue with this code. Statements don’t evaluate to a value, but `plus_one()` tries to return an `i32` with only a statement in the function body. In this output, Rust gives an option to rectify this: it suggests removing the semicolon, which would fix the error. - -In practice, Rust programmers don’t often think about these rules at this level. On a practical level, you should remember that you usually have a semicolon at the end of most lines, but ... - - -<-- thinking about this more, I did think of one: calling functions. foo() is an expression, and so foo() bar() is invalid. but adding ; to make them statements is okay, foo(); bar(); Maybe i can work up an example after all, what do you think? --> - - - - -### Returning Multiple Values - -By default, functions can only return single values. There’s a trick, however to get them to return multiple values. Remember how we used `()`s to create complex bindings in the "Creating Multiple Bindings" section on page XX? - -```rust -fn main() { - let (x, y) = (5, 6); -} -``` - -Braces used in this way form a *tuple*, which is a collection of elements that isn't assigned a name. Tuples are also a basic data type in Rust, and we'll cover them in detail in the "Tuples" section later in this chapter. For our purposes now, we can use tuples to return multiple values from functions, as so: - -```rust -fn main() { - let (x, y) = two_numbers(); - - println!("The value of x is: {}", x); - println!("The value of y is: {}", y); -} - -fn two_numbers() -> (i32, i32) { - (5, 6) -} -``` - - - - - -Running this will give us the values: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -The value of x is: 5 -The value of y is: 6 -``` - - - -Let's look at this more closely. First, we're assigning the return value of `two_numbers()` to `x` and `y`: - -```rust -fn two_numbers() -> (i32, i32) { - (5, 6) -} -``` - - - -In plain English, the `(i32, i32)` syntax translates to, “a tuple with two `i32`s in it." These two types are then applied to the tuple to be returned by the function block. In this case, that tuple contains the values `5` and `6`. This tuple is returned, and assigned to `x` and `y`: - -```rust,ignore -let (x, y) = two_numbers(); -``` - -See how all these bits fit together? We call this behavior of `let` ‘destructuring’, because it takes the structure of the expression that follows the `=` and takes it apart. - -## Data Types in Rust - -We’ve seen that every value in Rust is of a certain *type*, which tells Rust what kind of data is being given so it knows how to work with that data. As described in the "Type Inference and Annotation" section, you can rely on Rust's ability to infer types to figure out the type of a binding, or you can annotate it explicitly if needed. In this section, we'll look at a number of types built into the language itself. We'll look at two subsets of Rust data types: scalar and compound. - -### Type Inference and Annotation - - - - - -Rust is a *statically typed* language, which means that we must know the types of all bindings at compile time. However, you may have noticed that we didn’t declare a type for `x` or `y` in our previous examples. - - - -This is because Rust can often tell the type of a binding without you having to declare it. Annotating every single binding with a type can take uneccesary time and make code noisy. To avoid this, Rust uses *type inference*, meaning that it attempts to infer the types of your bindings from how the binding is used. Let’s look at the the first `let` statement you wrote again: - -```rust -fn main() { - let x = 5; -} -``` - - - -When we bind `x` to `5`, the compiler determines that `x` should be a numeric type based on the value it is bound to. Without any other information, it sets the `x` variable's type to `i32` (a thirty-two bit integer type) by default. We’ll talk more about Rust’s basic types in Section 3.3. - - - -If we were to declare the type with the variable binding, that would be called a *type annotation*. A `let` statement like that would look like this: - -```text - -let PATTERN: TYPE = VALUE; - -``` - - - -The `let` statement now has a colon after the `PATTERN`, followed by the `TYPE` name. Note that the colon and the `TYPE` go _after_ the `PATTERN`, not inside the pattern itself. Given this structure, here's how you'd rewrite `let x = 5` to use type annotation: - -```rust - -fn main() { - - let x: i32 = 5; - -} - -``` - -This does the same thing as `let x = 5` but explicitly states that `x` should be of the `i32` type. This is a simple case, but more complex patterns with multiple bindings can use type annotation, too. A binding with two variables would look like this: - - - -```rust - -fn main() { - - let (x, y): (i32, i32) = (5, 6); - -} - -``` - - - -In the same way as we place the `VALUE` and the `PATTERN` in corresponding positions, we also match up the position of the `TYPE` with the `PATTERN` it corresponds to. - - - - - - - - - -### Scalar Types - -A *scalar* type is one that represents a single value. There are four key scalar types in Rust: integers, floating point numbers, booleans, and characters. You'll likely recognize these from other programming languages, but let's jump into how they work in Rust. - - - -#### Integer Types - - - - -An *integer* is a number without a fractional component. We've used one integer type already in this chapter, the `i32` type. This type declaration indicates that the value it's associated with should be a signed integer (hence the `i`) for a 32-bit system. There are a number of built-in integer types in Rust, shown in Table 3-1. - -| Length | signed | unsigned | -|--------|--------|----------| -| 8-bit | i8 | u8 | -| 16-bit | i16 | u16 | -| 32-bit | i32 | u32 | -| 64-bit | i64 | u64 | -| arch | isize | usize | - -*Table 3-1: Integer types in Rust. The code, for example i32, is used to define a type in a function.* - - - -Each variant can be either signed or unsigned, and has an explicit size. Signed and unsigned merely refers to whether the number can be negative or positive. An unsigned number can only be positive, while a signed number can be either positive or negative. It's like writing numbers on paper: when the sign matters, a number is shown with a plus sign or minus sign, but when it's safe to assume the number is positive, it's shown with no sign. Signed numbers are stored using two’s complement representation. - - - - -Finally, the `isize` and `usize` types depend on the kind of computer your program is running on: 64-bits if you're on a 64-bit architecture, and 32-bits if you’re on a 32-bit architecture. - - - - - -So how do you know which type of integer to use? If you're unsure, Rust's defaults are generally good choices, and integer types default to `i32`: it’s generally the fastest, even on 64-bit systems. The primary situation in which you'd need to specify `isize` or `usize` is when indexing some sort of collection, which we'll talk about in the "Arrays" section. - - - - -#### Floating-Point Types - -Rust also has two primitive types for *floating-point numbers*, which are just numbers with decimal points, as usual. Rust's floating-point types are `f32` and `f64`, which are 32 bits and 64 bits in size, respectively. The default type is `f64`, as it’s roughly the same speed as `f32`, but has a larger precision. Here's an example showing floating-point numbers in action: - - - - -```rust -fn main() { - let x = 2.0; // f64 - - let y: f32 = 3.0; // f32 -} -``` - -Floating-point numbers are represented according to the IEEE-754 standard. The `f32` type is a single-precision float, while `f64` has double-precision. - - - - -#### Numeric Operations - -Rust supports the usual basic mathematic operations you’d expect for all of these number types--addition, subtraction, multiplication, division, and modulo. This code shows how you'd use each one in a `let` statement: - -```rust -fn main() { - // addition - let sum = 5 + 10; - - // subtraction - let difference = 95.5 - 4.3; - - // multiplication - let product = 4 * 30; - - // division - let quotient = 56.7 / 32.2; - - // modulus - let remainder = 43 % 5; -} - -``` - -Each expression in these statements uses a mathematical operator and evaluates to a single value, which is then bound to a variable. - - - - -#### The Boolean Type - -As in most other programming languages, a boolean type has two possible values: `true` and `false`. The boolean type in Rust is specified with `bool`. For example: - -```rust -fn main() { - let t = true; - - let f: bool = false; // with explict type annotation -} -``` - -The main way to consume boolean values is through conditionals like an `if` statement. We’ll cover how `if` statements work in Rust in the "Control Flow" section of this chapter. - -#### The Character Type - -So far we’ve only worked with numbers, but Rust supports letters too. Rust’s `char` type is the language's most primitive alphabetic type, and this code shows one way to use it: - -```rust -fn main() { - let c = 'z'; - - let z = 'ℤ'; -} -``` - -Rust’s `char` represents a Unicode Scalar Value, which means that it can represent a lot more than just ASCII. (You can learn more about Unicode Scalar Values at *http://www.unicode.org/glossary/#unicode_scalar_value*) A "character" isn’t really a concept in Unicode, however, so your human intutition for what a "character" is may not match up with what a `char` is in Rust. It also means that `char`s are four bytes each. - - - - - - - -### Compound Types - -*Compound types* can group multiple values of other types into another type. Rust has two primitive compound types: tuples and arrays. You can put a compound type inside a compound type as well. - - - - -#### Grouping Values into Tuples - -We’ve seen tuples already, when binding or returning multiple values at once. A tuple is a general way of grouping together some number of other values with distinct types into one compound type. The number of values is called the *arity* of the tuple. - -We create a tuple by writing a comma-separated list of values inside parentheses. Each position in the tuple has a distinct type, as in this example: - -```rust -fn main() { - let tup: (i32, f64, u8) = (500, 6.4, 1); -} -``` - -Note that, unlike the examples of multiple bindings, here we bind the single name `tup` to the entire tuple, emphasizing the fact that a tuple is considered a single compound element. We can then use pattern matching to destructure this tuple value, like this: - -```rust -fn main() { - let tup: (i32, f64, u8) = (500, 6.4, 1); - - let (x, y, z) = tup; - - println!("The value of y is: {}", y); -} -``` - -In this program, we first create a tuple, and bind it to the name `tup`. We then use a pattern with `let` to -take `tup` and turn it into three separate bindings, `x`, `y`, and `z`. This is called ‘destructuring’, because -it breaks the single tuple into three parts. - -Finally, we print the value of `x`, which is `6.4`. - -#### Tuple Indexing - -In addition to destructuring through pattern matching, we can also access a tuple element directly by using a period (`.`) followed by the index of the value we want to access. For example: - -```rust -fn main() { - let x: (i32, f64, u8) = (500, 6.4, 1); - - let five_hundred = x.0; - - let six_point_four = x.1; - - let one = x.2; -} -``` - - - - -This program creates a tuple, `x`, and then makes new bindings to each element by using their index. - -As with most programming languages, the first index in a tuple is 0. - - - -#### Single-Element Tuples - -Not everything contained within parentheses is a tuple in Rust. For example, a `(5)` may be a tuple, or just a `5` in parentheses. To disambiguate, use a comma for single-element tuples, as in this example: - -```rust -fn main() { - let x = (5); - - let x = (5,); -} - -``` - - - -In the first `let` statement, because `(5)` has no comma, it's a simple i32 and not a tuple. In the second `let` example, `(5,)` is a tuple with only one element. - -### Arrays - -So far, we’ve only represented single values in a binding. Sometimes, though, it’s useful to bind a name to more than one value. Data structures that contain multiple values are called *collections*, and arrays are the first type of Rust collection we’ll learn about. - - - - - -In Rust, arrays look like this: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; -} -``` - -The values going into an array are written as a comma separated list inside square brackets. Unlike a tuple, -every element of an array must have the same type. - - - - -#### Type Annotation for Arrays - -When you specify an array’s type, you'd do so as such: - -```rust -fn main() { - let a: [i32; 5] = [1, 2, 3, 4, 5]; -} -``` - -Much like in a variable binding that uses type annotation, the array's type and length come after the pattern name and a colon. This array has `5` values, which are of the `i32` type. Unlike the values themselves, the type and array length are separated by a semicolon. - -####Accessing and Modifying Array Elements - -An array is a single chunk of memory, allocated on the stack. We can access elements of an array using indexing, like this: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; - - let first = a[0]; - let second = a[1]; -} -``` - - - - -In this example, the `first` variable will bind to `1` at index `[0]` in the array, and `second` will bind to `2` at index `[1]` in the array. Note that these values are copied out of the array and into `first` and `second` when the `let` statement is called. That means if the array changes after the `let` statements, these bindings will not, and the two variables should retain their values. For example, imagine you have the following code: - - - -```rust -fn main() { - let mut a = [1, 2, 3, 4, 5]; - - let first = a[0]; - - a[0] = 7; - - println!("The value of first is: {}", first); -} -``` - - - - -First, notice the use of `mut` in the array declaration. We had to declare array `a` as `mut` to override Rust's default immutability. The line `a[0] = 7;` modifies the element at index 0 in the array, changing its value to `7`. This happens after `first` is bound to the original value at index 0, so `first` should still be equal `1`. Running the code will show this is true: - -```rust -The value of first is: 1 -``` - -Since `a[0]` didn't change until after `first` was assigned a value, the `println` macro replaced the `{}` with `1`, as expected. - - - - - -## Macros and Data Structures - -Now that we've discussed data structures a little, there are a couple of relevant macro concepts we should cover: the `panic!` macro and `Debug`, which is a new way of printing data to the terminal. - - - - -### Rectifying Invalid Indexes with `Panic!` - -Rust calls the `panic` macro when a program tries to access elements of an array (or any other data structure) and gives an invalid index. For an example, use the `functions` project we created on page XX and change your *src/main.rs* to look like this: - -```rust,should_panic -fn main() { - let a = [1, 2, 3, 4, 5]; - - let invalid = a[10]; - - println!("The value of invalid is: {}", invalid); -} -``` - -This program tries to access an element at index 10 in the `a` array. If we run it, we will get an error like this: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -thread ‘
’ panicked at ‘index out of bounds: the len is 5 but the index is 10’, src/main.rs:4 -Process didn’t exit successfully: `target/debug/functions` (exit code: 101) -``` - -The output tells us that our thread panicked, and that our program didn’t exit successfully. It also gives the reason: we requested an index of 10 from an array with a length of 5. - -So why did this cause Rust to panic? An array knows how many elements it holds. When we attempt to access an element using indexing, Rust will check that the index we've specified is less than the array length. If the index is greater than the length, it will panic. This is our first example of Rust’s safety principles in action. In many low-level languages, this kind of check is not done, and when you provide an incorrect index, invalid memory can be accessed. Rust protects us against this kind of error. We'll discuss more of Rust’s error handling in Chapter xx. - -### Using Debug in the println Macro - -So far, we’ve been printing values using `{}` in a `println` macro. If we try that with an array, however, we'll get an error. Say we have the following program: - -```rust,ignore -fn main() { - let a = [1, 2, 3, 4, 5]; - - println!("a is: {}", a); -} -``` - -This code tries to print the `a` array directly, which may seem innocuous. But running it produces the following output: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) -src/main.rs:4:25: 4:26 error: the trait `core::fmt::Display` is not implemented for the type `[_; 5]` [E0277] -src/main.rs:4 println!(“a is {}”, a); - ^ -:2:25: 2:56 note: in this expansion of format_args! -:3:1: 3:54 note: in this expansion of print! (defined in ) -src/main.rs:4:5: 4:28 note: in this expansion of println! (defined in ) -src/main.rs:4:25: 4:26 help: run `rustc --explain E0277` to see a detailed explanation -src/main.rs:4:25: 4:26 note: `[_; 5]` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string -src/main.rs:4:25: 4:26 note: required by `core::fmt::Display::fmt` -error: aborting due to previous error -``` - - - - -Whew! The core of the error is this part: the trait `core::fmt::Display` is not -implemented. We haven’t discussed traits yet, so this is bound to be confusing! -Here’s all we need to know for now: `println!` can do many kinds of formatting. -By default, `{}` implements a kind of formatting known as `Display`: output -intended for direct end-user consumption. The primitive types we’ve seen so far -implement `Display`, as there’s only one way you’d show a `1` to a user. But -with arrays, the output is less clear. Do you want commas or not? What about -the `[]`s? - -More complex types in the standard library do not automatically implement `Display` formatting. Instead, Rust implements another kind of formatting, also intended for the programmer. This formatting type is called `Debug`. To ask `println!` to use `Debug` formatting, we include `:?` in the print string, like this: - - - - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; - - println!("a is {:?}", a); -} -``` - -If you run this, it should print the five values in the `a` array as desired: - -```bash -$ cargo run - Compiling functions v0.1.0 (file:///projects/functions) - Running `target/debug/functions` -a is [1, 2, 3, 4, 5] -``` - -You’ll see this repeated later, with other types. We’ll cover traits fully in Chapter 9. - -## Comments - -All programmers strive to make their code easy to understand, but sometimes some extra explanation is warranted. In these cases, we leave notes in our source code that the compiler will ignore. These notes are called *comments*. - -Here’s a simple comment: - -```rust -// Hello, world. -``` - -In Rust, comments must start with two slashes, and will last until the end of the line. For comments that extend beyond a single line, you'll need to include `//` on each line, like this: - -```rust -// So we’re doing something complicated here, long enough that we need -// multiple lines of comments to do it! Whew! Hopefully, this comment will -// explain what’s going on. -``` - -Comments can also be placed at the end of lines of code: - -```rust -fn main() { - let lucky_number = 7; // I’m feeling lucky today. -} -``` - -But you’ll more often see them above, like so: - -```rust -fn main() { - // I’m feeling lucky today. - let lucky_number = 7; -} -``` - -That’s all there is to it. Comments are not particularly complicated. - -### Documentation Comments - - - - -Rust has another kind of comment: a *documentation comment*. These comments don’t affect the way that the code works, but they do work with Rust’s tools. More specifically, the `rustdoc` tool can read documentation comments and produce HTML documentation from them. Documentation comments use an extra slash, like this: - -```rust -/// The foo function doesn’t really do much. -fn foo() { - -} - -/// Documentation comments can use -/// multiple line comments too, -/// like we did before. -fn bar() { - -} -``` - -The `rustdoc` tool would interpret each comment in this example as documenting the thing -that follows it. The first comment would be used to document the `foo()` function, and the second comment would document the `bar()` function. - -Because documentation comments have semantic meaning to `rustdoc`, the compiler will pay attention to the placement of your documentation comments. For example, a program containing only this: - -```rust,ignore -/// What am I documenting? -``` - -Will give the following compiler error: - -```text -src/main.rs:1:1: 1:27 error: expected item after doc comment -src/main.rs:1 /// What am I documenting? - ^~~~~~~~~~~~~~~~~~~~~~~~~~ -``` - -This happens because Rust expects a document comment to be associated with whatever code comes directly after it, so it sees that a document comment alone must be a mistake. - - - -## Control Flow with `if` - - - - -> Two roads diverged in a yellow wood, -> And sorry I could not travel both -> And be one traveler, long I stood -> And looked down one as far as I could -> To where it bent in the undergrowth; -> -> - Robert Frost, “The Road Not Taken” - - - - - - - - -In Rust, as in most programming languages, an `if` expression allows us to branch our code depending on conditions. We provide a condition, and then say, `if` this condition is met, then run this block of code; `if` the condition is not met, run a different block of code (or stop the program). - -Let’s make a new project to explore `if`. Navigate to your projects directory, -and use Cargo to make a new project called `branches`: - -```bash -$ cargo new --bin branches -$ cd branches -``` - -Write this sample program using `if` and save it in the *branches* directory: - -```rust -fn main() { - let condition = true; - - if condition { - println!("condition was true"); - } else { - println!("condition was false"); - } -} -``` - -The `condition` variable is a boolean; here, it's set to true. All `if` statements start with `if`, which is followed by a condition. The block of code we want to execute if the condition is true goes immediately after the condition, inside curly braces. These blocks are sometimes called ‘arms’. We can also include an `else` statement, which gives the program a block of code to execute should `condition` evaluate to false. - -Try running this code, and you should see output like this: - -```bash -$ cargo run - Compiling branches v0.1.0 (file:///projects/branches) - Running `target/debug/branches` -condition was true -``` - - - - -Before we talk about what’s happening here, let’s try changing the value of `condition` to `false` as follows: - -```rust - let condition = false; -``` - -Run the program again, and look at the output: - -```bash -$ cargo run - Compiling branches v0.1.0 (file:///projects/branches) - Running `target/debug/branches` -condition was false -``` - -This time the second block of code is run, the `else` block is executed. This is the very basic structure of `if`: _if_ the condition is true, then execute some code. If it’s not true, then execute some other code. When an `else` block is included, that "other code" is the code in the `else` block. You could also not use an `else` expression, as in this example: - -```rust -fn main() { - let condition = false; - - if condition { - println!("condition was true"); - } -} -``` - -In this case, nothing would be printed, because there is no code after the `if` block. - - - - -It’s also worth noting that `condition` here _must_ be a `bool`. To see what happens if the condition isn't a `bool`, try running this code: - - - - -```rust,ignore -fn main() { - let condition = 5; - - if condition { - println!("condition was five"); - } -} -``` - -The `condition` variable is assigned a value of `5` this time, and Rust will complain about it: - -```bash - Compiling branches v0.1.0 (file:///projects/branches) -src/main.rs:4:8: 4:17 error: mismatched types: - expected `bool`, - found `_` -(expected bool, - found integral variable) [E0308] -src/main.rs:4 if condition { - ^~~~~~~~~ -src/main.rs:4:8: 4:17 help: run `rustc --explain E0308` to see a detailed explanation -error: aborting due to previous error -Could not compile `branches`. -``` - -The error tells us that Rust expected a `bool`, but got an integer. Rust will not automatically try to convert non-boolean types to a boolean here. We must be explicit. - - - - -### Multiple Conditions with `else if` - -We can set multiple coniditions by combining `if` and `else` in an `else if` expression. For example: - -```rust -fn main() { - let number = 5; - - if number == 3 { - println!("condition was 3"); - } else if number == 4 { - println!("condition was 4"); - } else if number == 5 { - println!("condition was 5"); - } else { - println!("condition was something else"); - } -} -``` - -This program three possible paths it can take after checking the condition, and if you try running it, you should see output like this: - -```bash -$ cargo run - Compiling branches v0.1.0 (file:///projects/branches) - Running `target/debug/branches` -condition was 5 -``` - -When this program executes, it will check each `if` expression in turn, and execute the first body for which the condition holds true. - - - - -Using too many `else if` expressions can clutter your code, so if you find yourself with more than one, you may want to look at refactoring your code. In Chapter XX, we'll talk about a powerful Rust branching construct called `match` for these cases. - -### Using `if` in a Binding - -The last detail you need to learn about `if` is that it’s an expression. That means that we can use it on the right hand side of a `let` binding, for instance: - -```rust -fn main() { - let condition = true; - let number = if condition { - 5 - } else { - 6 - }; - - println!("The value of number is: {}", number); -} -``` - -The `number` variable will be bound to a value based on the outcome of the `if` expression. Let’s run this to see what happens: - -```bash -$ cargo run - Compiling branches v0.1.0 (file:///projects/branches) - Running `target/debug/branches` -The value of number is: 5 -``` - -Remember, blocks of code evaluate to the last expression in them, and numbers by themselves are also expressions. In this case, the value of the whole `if` expression depends on which block of code executes. This means that the value in both arms of the `if` must be the same type; in the previous example, they were both `i32` integers. But what happens if the types are mismatched, as in the following example? - -```rust,ignore -fn main() { - let condition = true; - - let number = if condition { - 5 - } else { - "six" - }; - - println!("The value of number is: {}", number); -} -``` - -The expression in one block of the `if` statement, is an integer and the expresion in the other block is a string. If we try to run this, we’ll get an error: - -```bash - Compiling branches v0.1.0 (file:///projects/branches) -src/main.rs:4:18: 8:6 error: if and else have incompatible types: - expected `_`, - found `&‘static str` -(expected integral variable, - found &-ptr) [E0308] -src/main.rs:4 let number = if condition { -src/main.rs:5 5 -src/main.rs:6 } else { -src/main.rs:7 "six" -src/main.rs:8 }; -src/main.rs:4:18: 8:6 help: run `rustc --explain E0308` to see a detailed explanation -error: aborting due to previous error -Could not compile `branches`. -``` - -The `if` and `else` arms have value types that are incompatible, and Rust tells us exactly where to find the problem in our program. This can’t work, because variable bindings must have a single type. - - - - -## Control Flow with Loops - -It’s often useful to be able to execute a block of code more than one time. For this, Rust has several constructs called *loops*. A loop runs through the code inside it to the end and then starts immediately back at the beginning. To try out loops, let’s make a new project. Navigate to your *projects* folder and use Cargo to make a new project: - -```bash -$ cargo new --bin loops -$ cd loops -``` - -There are three kinds of loops in Rust: `loop`, `while`, and `for`. Let’s dig -in. - -### Repeating Code with `loop` - - - -The `loop` keyword tells Rust to execute a block of code over and over again forever, or until we explicitly kill it. - -For an example, change the *src/main.rs* file in your *loops* directory to look like this: - -```rust,ignore -fn main() { - loop { - println!("again!"); - } -} -``` - -If we run this program, we’ll see `again!` printed over and over continuously until we kill the program manually. Most terminals support a keyboard shortcut, `control-c`, to kill a program stuck in a continual loop. Give it a try: - -```bash -$ cargo run - Compiling loops v0.1.0 (file:///projects/loops) - Running `target/debug/loops` -again! -again! -again! -again! -^Cagain! -``` -That `^C` there is where I hit `control-c`. Fortunately, Rust provides another, more reliable way to break out of a loop. We can place the `break` keyword within the loop to tell the program when to stop executing the loop. Try this version out of the program: - -```rust -fn main() { - loop { - println!("once!"); - break; - } -} -``` - -If you run this program, you’ll see that it only executes one -time: - -```bash -$ cargo run - Compiling loops v0.1.0 (file:///projects/loops) - Running `target/debug/loops` -once! -``` - - -When a Rust program hits a `break` statement, it will exit the current loop. This on its own is not very useful; if we wanted to print somtheing just once, we wouldn't put it in a loop. This is where conditions come in again. - - - - -### Conditional Loops With `while` - -To make `break` useful, we need to give our program a condition. While the condition is true, the loop runs. When the condition ceases to be true, the `break` code runs, stopping the loop. - - - - -Try this example: - -```rust - -fn main() { - let mut number = 3; - - loop { - if number != 0 { - println!("{}!", number); - - number = number - 1; - } else { - break; - } - } - - println!("LIFTOFF!!!"); -} -``` - -If we run this, we’ll get: - -```bash - Compiling loops v0.1.0 (file:///projects/loops) - Running `target/debug/loops` -3! -2! -1! -LIFTOFF!!! -``` - - - - -This program loops three times, counting down each time. Finally, after the -loop, it prints another message, then exits. - -The core of this example is in the combination of these three constructs: - -```rust,ignore - loop { - if number != 0 { - // do stuff - } else { - break; - } -``` - -We want to `loop`, but only while some sort of condition is true. As soon as it isn't, we want to `break` out of the loop. This pattern is so common that Rust has a more efficient language construct for it, called a `while` loop. Here's the same example, but using `while` instead: - - -```rust -fn main() { - let mut number = 3; - - while number != 0 { - println!("{}!", number); - - number = number - 1; - } - - println!("LIFTOFF!!!"); -} -``` - -This gets rid of a lot of nesting, and it's more clear. While a condition holds, -run this code. - -### Looping Though a Collection with `for` - -We can use this `while` construct to loop over the elements of a collection, like an array. For example: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; - let mut index = 0; - - while index < 5 { - println!("the value is is: {}", a[index]); - - index = index + 1; - } -} -``` - -Here, we're counting up through the elements in the array. We start at index 0, then loop until we hit the final index of our array (that is, when `index < 5` is no longer true). Running this will print out every element of the array: - -```bash -$ cargo run - Compiling loops v0.1.0 (file:///projects/loops) - Running `target/debug/loops` -the value is: 1 -the value is: 2 -the value is: 3 -the value is: 4 -the value is: 5 -``` - - -All five array values appear in the terminal, as expected. Even though `index` will reach a value of `6` at some point, the loop stops executing before trying to fetch a sixth value from the array. - -This approach is error-prone, though; we could trigger a `panic!` by getting the index length incorrect. It's also slow, as the compiler needs to perform the conditional check on every element on every iteration through the loop. - -As a more efficient alternative, we can use a `for` loop. A `for` loop looks something like this: - -```rust -fn main() { - let a = [1, 2, 3, 4, 5]; - - let mut index = 0; - - for element in a.iter() { - println!("the value is: {}", element); - } -} - -``` - -** NOTE: see [https://github.com/rust-lang/rust/issues/25725#issuecomment-166365658](https://github.com/rust-lang/rust/issues/25725#issuecomment-166365658), we may want to change this ** - - -If we run this, we'll see the same output as the previous example. - - - -** I'm going to leave it at this for now until we decide how we want to do it** - diff --git a/nostarch/chapter5.md b/nostarch/chapter5.md deleted file mode 100644 index 17bfb7a226..0000000000 --- a/nostarch/chapter5.md +++ /dev/null @@ -1,697 +0,0 @@ -# Structs - -So far, all of the data types we’ve seen allow us to have a single value -at a time. `struct`s give us the ability to package up multiple values and -keep them in one related structure. - -Let’s write a program which calculates the distance between two points. -We’ll start off with single variable bindings, and then refactor it to -use `struct`s instead. - -Let’s make a new project with Cargo: - -```bash -$ cargo new --bin points -$ cd points -``` - -Here’s a short program which calculates the distance between two points. Put -it into your `src/main.rs`: - -```rust -fn main() { - let x1 = 0.0; - let y1 = 5.0; - - let x2 = 12.0; - let y2 = 0.0; - - let answer = distance(x1, y1, x2, y2); - - println!("Point 1: ({}, {})", x1, y1); - println!("Point 2: ({}, {})", x2, y2); - println!("Distance: {}", answer); -} - -fn distance(x1: f64, y1: f64, x2: f64, y2: f64) -> f64 { - let x_squared = f64::powi(x2 - x1, 2); - let y_squared = f64::powi(y2 - y1, 2); - - f64::sqrt(x_squared + y_squared) -} -``` - -Let's try running this program with `cargo run`: - -```bash -$ cargo run - Compiling points v0.1.0 (file:///projects/points) - Running `target/debug/points` -Point 1: (0, 5) -Point 2: (12, 0) -Distance: 13 -``` - -Let's take a quick look at `distance()` before we move forward: - -```rust -fn distance(x1: f64, y1: f64, x2: f64, y2: f64) -> f64 { - let x_squared = f64::powi(x2 - x1, 2); - let y_squared = f64::powi(y2 - y1, 2); - - f64::sqrt(x_squared + y_squared) -} -``` - -To find the distance between two points, we can use the Pythagorean Theorem. -The theorem is named after Pythagoras, who was the first person to mathematically -prove this formula. The details aren't that important, to be honest. There's a few -things that we haven't discussed yet, though. - -```rust,ignore -f64::powi(2.0, 3) -``` - -The double colon (`::`) here is a namespace operator. We haven’t talked about -modules yet, but you can think of the `powi()` function as being scoped inside -of another name. In this case, the name is `f64`, the same as the type. The -`powi()` function takes two arguments: the first is a number, and the second is -the power that it raises that number to. In this case, the second number is an -integer, hence the ‘i’ in its name. Similarly, `sqrt()` is a function under the -`f64` module, which takes the square root of its argument. - -## Why `struct`s? - -Our little program is okay, but we can do better. The key is in the signature -of `distance()`: - -```rust,ignore -fn distance(x1: f64, y1: f64, x2: f64, y2: f64) -> f64 { -``` - -The distance function is supposed to calculate the distance between two points. -But our distance function calculates some distance between four numbers. The -first two and last two arguments are related, but that’s not expressed anywhere -in our program itself. We need a way to group `(x1, y1)` and `(x2, y2)` -together. - -We’ve already discussed one way to do that: tuples. Here’s a version of our program -which uses tuples: - -```rust -fn main() { - let p1 = (0.0, 5.0); - - let p2 = (12.0, 0.0); - - let answer = distance(p1, p2); - - println!("Point 1: {:?}", p1); - println!("Point 2: {:?}", p2); - println!("Distance: {}", answer); -} - -fn distance(p1: (f64, f64), p2: (f64, f64)) -> f64 { - let x_squared = f64::powi(p2.0 - p1.0, 2); - let y_squared = f64::powi(p2.1 - p1.1, 2); - - f64::sqrt(x_squared + y_squared) -} -``` - -This is a little better, for sure. Tuples let us add a little bit of structure. -We’re now passing two arguments, so that’s more clear. But it’s also worse. -Tuples don’t give names to their elements, and so our calculation has gotten -much more confusing: - -```rust,ignore -p2.0 - p1.0 -p2.1 - p1.1 -``` - -When writing this example, your authors almost got it wrong themselves! Distance -is all about `x` and `y` points, but now it’s all about `0` and `1`. This isn’t -great. - -Enter `struct`s. We can transform our tuples into something with a name: - -```rust,ignore -let p1 = (0.0, 5.0); - -struct Point { - x: f64, - y: f64, -} - -let p1 = Point { x: 0.0, y: 5.0 }; -``` - -Here’s what declaring a `struct` looks like: - -```text -struct NAME { - NAME: TYPE, -} -``` - -The `NAME: TYPE` bit is called a ‘field’, and we can have as many or as few of -them as you’d like. If you have none of them, drop the `{}`s: - -```rust -struct Foo; -``` - -`struct`s with no fields are called ‘unit structs’, and are used in certain -advanced situations. We will just ignore them for now. - -You can access the field of a struct in the same way you access an element of -a tuple, except you use its name: - -```rust,ignore -let p1 = (0.0, 5.0); -let x = p1.0; - -struct Point { - x: f64, - y: f64, -} - -let p1 = Point { x: 0.0, y: 5.0 }; -let x = p1.x; -``` - -Let’s convert our program to use our `Point` `struct`. Here’s what it looks -like now: - -```rust -#[derive(Debug,Copy,Clone)] -struct Point { - x: f64, - y: f64, -} - -fn main() { - let p1 = Point { x: 0.0, y: 5.0}; - - let p2 = Point { x: 12.0, y: 0.0}; - - let answer = distance(p1, p2); - - println!("Point 1: {:?}", p1); - println!("Point 2: {:?}", p2); - println!("Distance: {}", answer); -} - -fn distance(p1: Point, p2: Point) -> f64 { - let x_squared = f64::powi(p2.x - p1.x, 2); - let y_squared = f64::powi(p2.y - p1.y, 2); - - f64::sqrt(x_squared + y_squared) -} -``` - -Our function signature for `distance()` now says exactly what we mean: it -calculates the distance between two `Point`s. And rather than `0` and `1`, -we’ve got back our `x` and `y`. This is a win for clarity. - -There’s one other thing that’s a bit strange here, this annotation on our -`struct` declaration: - -```rust,ignore -#[derive(Debug,Copy,Clone)] -struct Point { -``` - -We haven’t yet talked about traits, but we did talk about `Debug` when we -discussed arrays. This `derive` attribute allows us to tweak the behavior of -our `Point`. In this case, we are opting into copy semantics, and everything -that implements `Copy` must implement `Clone`. -# Method Syntax - -In the last section on ownership, we made several references to ‘methods’. -Methods look like this: - -```rust -let s1 = String::from("hello"); - -// call a method on our String -let s2 = s1.clone(); - -println!("{}", s1); -``` - -The call to `clone()` is attatched to `s1` with a dot. This is called ‘method -syntax’, and it’s a way to call certain functions with a different style. - -Why have two ways to call functions? We’ll talk about some deeper reasons -related to ownership in a moment, but one big reason is that methods look nicer -when chained together: - -```rust,ignore -// with functions -h(g(f(x))); - -// with methods -x.f().g().h(); -``` - -The nested-functions version reads in reverse: we call `f()`, then `g()`, then -`h()`, but it reads as `h()`, then `g()`, then `f()`. - -Before we get into the details, let’s talk about how to define your own -methods. - -## Defining methods - -We can define methods with the `impl` keyword. `impl` is short for -‘implementation’. Doing so looks like this: - -```rust -#[derive(Debug,Copy,Clone)] -struct Point { - x: f64, - y: f64, -} - -impl Point { - fn distance(&self, other: &Point) -> f64 { - let x_squared = f64::powi(other.x - self.x, 2); - let y_squared = f64::powi(other.y - self.y, 2); - - f64::sqrt(x_squared + y_squared) - } -} - -let p1 = Point { x: 0.0, y: 0.0 }; -let p2 = Point { x: 5.0, y: 6.5 }; - -assert_eq!(8.200609733428363, p1.distance(&p2)); -``` - -Let’s break this down. First, we have our `Point` struct from earlier in the -chapter. Next comes our first use of the `impl` keyword: - -``` -# #[derive(Debug,Copy,Clone)] -# struct Point { -# x: f64, -# y: f64, -# } -# -impl Point { -# fn distance(&self, other: &Point) -> f64 { -# let x_squared = f64::powi(other.x - self.x, 2); -# let y_squared = f64::powi(other.y - self.y, 2); -# -# f64::sqrt(x_squared + y_squared) -# } -} -# -# let p1 = Point { x: 0.0, y: 0.0 }; -# let p2 = Point { x: 5.0, y: 6.5 }; -# -# assert_eq!(8.200609733428363, p1.distance(&p2)); -``` - -Everything we put inside of the curly braces will be methods implemented on -`Point`. - -``` -# #[derive(Debug,Copy,Clone)] -# struct Point { -# x: f64, -# y: f64, -# } -# -# impl Point { - fn distance(&self, other: &Point) -> f64 { -# let x_squared = f64::powi(other.x - self.x, 2); -# let y_squared = f64::powi(other.y - self.y, 2); -# -# f64::sqrt(x_squared + y_squared) - } -# } -# -# let p1 = Point { x: 0.0, y: 0.0 }; -# let p2 = Point { x: 5.0, y: 6.5 }; -# -# assert_eq!(8.200609733428363, p1.distance(&p2)); -``` - -Next is our definition. This looks very similar to our previous definition of -`distance()` as a function: - -```rust -# #[derive(Debug,Copy,Clone)] -# struct Point { -# x: f64, -# y: f64, -# } -fn distance(p1: Point, p2: Point) -> f64 { -# let x_squared = f64::powi(p2.x - p1.x, 2); -# let y_squared = f64::powi(p2.y - p1.y, 2); -# -# f64::sqrt(x_squared + y_squared) -# } -``` - -Other than this, the rest of the example is familliar: an implementation of -`distance()`, and using the method to find an answer. - -There are two differences. The first is in the first argument. Instead of a name -and a type, we have written `&self`. This is what distinguishes a method from a -function: using `self` inside of an `impl` block. Because we already know that -we are implementing this method on `Point`, we don’t need to write the type of -`self` out. However, we have written `&self`, not only `self`. This is because -we want to take our argument by reference rather than by ownership. In other -words, these two forms are the same: - -```rust,ignore -fn foo(self: &Point) -fn foo(&self) -``` - -Just like any other parameter, you can take `self` in three forms. Here’s the -list, with the most common form first: - -```rust,ignore -fn foo(&self) // take self by reference -fn foo(&mut self) // take self by mutable reference -fn foo(self) // take self by ownership -``` - -In this case, we only need a reference. We don’t plan on taking ownership, and -we don’t need to mutate either point. Taking by reference is by far the most -common form of method, followed by a mutable reference, and then occasionally -by ownership. - -### Methods and automatic referencing - -We’ve left out an important detail. It’s in this line of the example: - -``` -# #[derive(Debug,Copy,Clone)] -# struct Point { -# x: f64, -# y: f64, -# } -# -# impl Point { -# fn distance(&self, other: &Point) -> f64 { -# let x_squared = f64::powi(other.x - self.x, 2); -# let y_squared = f64::powi(other.y - self.y, 2); -# -# f64::sqrt(x_squared + y_squared) -# } -# } -# -# let p1 = Point { x: 0.0, y: 0.0 }; -# let p2 = Point { x: 5.0, y: 6.5 }; -# -assert_eq!(8.200609733428363, p1.distance(&p2)); -``` - -When we defined `distance()`, we took both `self` and the other argument by -reference. Yet, we needed a `&` for `p2` but not `p1`. What gives? - -This feature is called ‘automatic referencing’, and calling methods is one -of the few places in Rust that has behavior like this. Here’s how it works: -when you call a method with `self.(`, Rust will automatically add in `&`s -or `&mut`s to match the signature. In other words, these three are the same: - -```rust -# #[derive(Debug,Copy,Clone)] -# struct Point { -# x: f64, -# y: f64, -# } -# -# impl Point { -# fn distance(&self, other: &Point) -> f64 { -# let x_squared = f64::powi(other.x - self.x, 2); -# let y_squared = f64::powi(other.y - self.y, 2); -# -# f64::sqrt(x_squared + y_squared) -# } -# } -# let p1 = Point { x: 0.0, y: 0.0 }; -# let p2 = Point { x: 5.0, y: 6.5 }; -p1.distance(&p2); -(&p1).distance(&p2); -Point::distance(&p1, &p2); -``` - -The first one looks much, much cleaner. Here’s another example: - -```rust -let mut s = String::from("Hello,"); - -s.push_str(" world!"); - -// The above is the same as: -// (&mut s).push_str(" world!"); - -assert_eq!("Hello, world!", s); -``` - -Because [`push_str()`] has the following signature: - -```rust,ignore -fn push_str(&mut self, string: &str) { -``` - -[`push_str()`]: http://doc.rust-lang.org/collections/string/struct.String.html#method.push_str - -This automatic referencing behavior works because methods have a clear receiver -— the type of `self` — and in most cases it’s clear given the receiver and name -of a method whether the method is just reading (so needs `&self`), mutating (so -`&mut self`), or consuming (so `self`). The fact that Rust makes borrowing -implicit for method receivers is a big part of making ownership ergonomic in -practice. - -## Methods can be called like functions - -Furthermore, if we have a method, we can also call it like a function: - -```rust -# #[derive(Debug,Copy,Clone)] -# struct Point { -# x: f64, -# y: f64, -# } -# -# impl Point { -# fn distance(&self, other: &Point) -> f64 { -# let x_squared = f64::powi(other.x - self.x, 2); -# let y_squared = f64::powi(other.y - self.y, 2); -# -# f64::sqrt(x_squared + y_squared) -# } -# } -# let p1 = Point { x: 0.0, y: 0.0 }; -# let p2 = Point { x: 5.0, y: 6.5 }; -let d1 = p1.distance(&p2); -let d2 = Point::distance(&p1, &p2); - -assert_eq!(d1, d2); -``` - -Instead of using `self.(`, we use `Point` and the namespace operator to call it -like a function instead. Because functions do not do the automatic referencing, -we must pass in `&p1` explicitly. - -While methods can be called like functions, functions cannot be called like -methods. If the first argument isn’t named `self`, it cannot be called like a -method. -# Generics - -We've been working with a `Point` struct that looks like this: - -```rust -#[derive(Debug,Copy,Clone)] -struct Point { - x: f64, - y: f64, -} -``` - -But what if we didn't want to always use an `f64` here? What about an `f32` for -when we need less precision? Or an `i32` if we only want integer coordinates? - -While our simple `Point` struct may be a bit too simple to bother making -generic in a real application, we're going to stick with it to show you the -syntax. Especially when building library code, generics allow for more code -re-use, and unlock a lot of powerful techniques. - -## Generic data types - -'Generics' let us write code that allows for several different types, while -letting us have one definition. A more generic `Point` would look like this: - -```rust -#[derive(Debug,Copy,Clone)] -struct Point { - x: T, - y: T, -} -``` - -There are two changes here, and they both involve this new `T`. The first change -is in the definition: - -```rust -# #[derive(Debug,Copy,Clone)] -struct Point { -# x: T, -# y: T, -# } -``` - -Our previous definition said, "We are defining a struct named Point." This -definition says something slightly different: "We are defining a struct named -Point with one type parameter `T`." - -Let's talk about this term 'type parameter'. We've already seen one other thing -called a 'parameter' in Rust: function parameters: - -```rust -fn plus_one(x: i32) -> i32 { - x + 1 -} -``` - -Here, `x` is a parameter to this function. We can call this function with a -different value, and `x` will change each time it's called: - -```rust -# fn plus_one(x: i32) -> i32 { -# x + 1 -# } -let six = plus_one(5); -let eleven = plus_one(10); -``` - -In the same way, a type parameter allows us to define a data type which can be -different each time we use it: - -```rust -#[derive(Debug,Copy,Clone)] -struct Point { - x: T, - y: T, -} - -let integral_point = Point { x: 5, y: 5 }; -let floating_point = Point { x: 5.0, y: 5.0 }; -``` - -Here, `integral_point` uses `i32` values for `T`, and `floating_point` uses -`f64` values. This also leads us to talk about the second change we made to `Point`: - -```rust -# #[derive(Debug,Copy,Clone)] -# struct Point { - x: T, - y: T, -# } -``` - -Instead of saying `x: i32`, we say `x: T`. This `T` is the same one that we -used above in the struct declaration. Because `x` and `y` both use `T`, they'll -be the same type. We could give them different types: - -```rust -#[derive(Debug,Copy,Clone)] -struct Point { - x: T, - y: OtherT, -} - -let different = Point { x: 5, y: 5.0 }; -let same = Point { x: 5.0, y: 5.0 }; -``` - -Here, instead of a single parameter, `T`, we have two: `T` and `OtherT`. Type -parameters have the same naming convention as other types: `CamelCase`. -However, you'll often see short, one-letter names used for types. `T` is very -common, because it's short for 'type', but you can name them something longer -if you'd like. In this version of `Point`, we say that `x` has the type `T`, -and `y` has the type `OtherT`. This lets us give them two different types, but -they don't have to be. - -## Generic functions - -Regular old functions can also take generic parameters, with a syntax that looks -very similar: - -```rust -fn foo(x: T) { - // ... -} -``` - -This `foo()` function has one generic parameter, `T`, and takes one argument, -`x`, which has the type `T`. Let's talk a little bit more about what this means. - - -## Generic methods - -We've seen how to define methods with the `impl` keyword. Our generic `Point` -can have generic methods, too: - -```rust -#[derive(Debug,Copy,Clone)] -struct Point { - x: T, - y: T, -} - -impl Point { - fn some_method(&self) { - // ... - } -} -``` - -We also need the `` after `impl`. This line reads, "We will be implementing -methods with one generic type parameter, `T`, for a type, `Point`, which takes -one generic type `T`." In a sense, the `impl` says "we will be using a type -`T`" and the `Point` says "that `T` is used for `Point`." In this simple -case, this syntax can feel a bit redundant, but when we get into some of Rust's -more advanced features later, this distinction will become more useful. - -## There's more to the story - -This section covered the basic syntax of generics, but it's not the full story. -For example, let's try to implement our `foo()` function: we'll have it print out -the value of `x`: - -```rust,ignore -fn foo(x: T) { - println!("x is: {}", x); -} -``` - -We'll get an error: - -```text -error: the trait `core::fmt::Display` is not implemented for the type `T` [E0277] -println!("x is: {}", x); - ^ -``` - -We can't print out `x`! The error messages reference something we talked about -breifly before, the `Display` trait. In order to implement this function, we -need to talk about traits. But we only need to talk about traits to implement -our own generic functions; we don't need this understanding to use them. So -rather than get into more details about this right now, let's talk about other -useful Rust data types, and we can come back to implementing generic functions -in the chapter about traits. - -For now, the important bits to understand: - -* Generic type parameters are kind of like function parameters, but for types - instead of values. -* Type parameters go inside `<>`s and are usually named things like `T`. - -With that, let's talk about another fundamental Rust data type: enums. diff --git a/nostarch/chapter6.md b/nostarch/chapter6.md deleted file mode 100644 index a6c438e4ad..0000000000 --- a/nostarch/chapter6.md +++ /dev/null @@ -1,738 +0,0 @@ -# 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, -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. - -Here’s an example of an enum: - -```rust -enum IpAddrKind { - V4, - V6, -} -``` - -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. - -We can create values of `IpAddrKind` like this: - -```rust -# enum IpAddrKind { -# V4, -# V6, -# } - -let four = IpAddrKind::V4; -let six = IpAddrKind::V6; -``` - -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, -we only know what kind it is. Given that you just learned about structs, you -might tackle this problem like this: - -```rust -enum IpAddrKind { - V4, - V6, -} - -struct IpAddr { - kind: IpAddrKind, - address: String, -} - -let home = IpAddr { - kind: IpAddrKind::V4, - address: String::from("127.0.0.1"), -}; - -let loopback = IpAddr { - kind: IpAddrKind::V6, - address: String::from("::1"), -}; -``` - -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: - -```rust -enum IpAddr { - V4(String), - V6(String), -} - -let home = IpAddr::V4(String::from("127.0.0.1")); - -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. -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: - -```rust -enum IpAddr { - V4(u32, u32, u32, u32), - V6(String), -} - -let home = IpAddr::V4(127, 0, 0, 1); - -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: - -```rust -struct Ipv4Addr { - // details elided -} - -struct Ipv6Addr { - // details elided -} - -enum IpAddr { - V4(Ipv4Addr), - V6(Ipv6Addr), -} -``` - -[IpAddr]: http://doc.rust-lang.org/std/net/enum.IpAddr.html - -Here’s an enum with a variety of types embedded in its variants: - -```rust -enum Message { - Quit, - Move { x: i32, y: i32 }, - Write(String), - ChangeColor(i32, i32, i32), -} -``` - -* `Quit` has no data associated with it at all. -* `Move` includes an anonymous struct inside of it. -* `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`. - - - - - - - - - - -# 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. - -Programming language design is often though 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. - -The inventor of this concept has this to say: - -> I call it my billion-dollar mistake. At that time, I was designing the first -> comprehensive type system for references in an object-oriented language. My -> goal was to ensure that all use of references should be absolutely safe, with -> checking performed automatically by the compiler. But I couldn't resist the -> temptation to put in a null reference, simply because it was so easy to -> implement. This has led to innumerable errors, vulnerabilities, and system -> crashes, which have probably caused a billion dollars of pain and damage in -> the last forty years. -> -> - Tony Hoare "Null References: The Billion Dollar Mistake" - -The problem with null values is twofold: first, a value can be null or not, at -any time. The second is that if you try to use a value that's null, you'll get -an error of some kind, depending on the language. Because this property is -pervasive, it's extremely easy to make this kind of error. - -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: - -```rust -enum Option { - Some(T), - None, -} -``` - -This type 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::`. - -[option]: ../std/option/enum.Option.html - -Here's an example of using `Option`: - -```rust -let some_number = Some(5); -let some_string = Some("a string"); - -// If we only say None, we need to tell Rust what type of Option we have. -let absent_number: Option = None; -``` - -Let's dig in. First, you'll notice that we used the `` syntax when defining -`Option`: it's a generic enum. `Option` has two variants: `Some`, which -contains a `T`, and `None`, which has no data associated with it. In some -sense, `None` means 'null', and `Some` means 'not null'. So why is this any -better than null? - -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 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] - -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 -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. - -[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`. -# 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` 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. - -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 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: - -```text -None => None, -``` - -Does `Some(5)` match `None`? No, it's the wrong variant. So let's continue. - -```text -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 `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: - -```text -None => None, -``` - -Does `None` match `None`? Yup! And so we return `None`. There's no value to add -to. - -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 -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. - -## Matches are exhaustive - -There's one other aspect of `match` we didn't talk about. Consider this version -of `plus_one()`: - -```rust,ignore -fn plus_one(x: Option) -> Option { - match x { - Some(i) => Some(i + 1), - } -} -``` - -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] -match x { - Some(i) => Some(i + 1), -} -``` - -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: - -```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, 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; -match some_u8_value { - 1 => println!("one"), - 3 => println!("three"), - 5 => println!("five"), - 7 => println!("seven"), - _ => (), -} -``` - -The `_` pattern will match all the other cases, and `()` will do nothing, it's -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. -# if let - -There's one more advanced control flow structure we haven't discussed: `if -let`. Imagine we're in a situation like this: - -```rust -# let some_option = Some(5); -match some_option { - Some(x) => { - // do something with x - }, - None => {}, -} -``` - -We care about the `Some` case, but don't want to do anything with the `None` -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 -others." - -Enter `if let`: - -```rust -# let some_option = Some(5); -if let Some(x) = some_option { - // do something with x -} -``` - -`if let` takes a pattern and an expression, separated by an `=`. It works -exactly like a `match`, where the expression is given to the `match` and the -pattern is its first arm. In other words, you can think of `if let` as syntax -sugar: - -```rust,ignore -if let pattern = expression { - body -} - -match expression { - pattern => body, - _ => {} -} -``` - -And in fact, we can include an `else` and it becomes the body of the `_` -case: - -```rust,ignore -if let pattern = expression { - body -} else { - else_body -} - -match expression { - pattern => body, - _ => else_body, -} -``` - -In other words, it's the high-level construct we were originally looking for: -do something with a single pattern. -# 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 - 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 `@`: From 8a5f54e2e22b208cd1886c13154b4325cd076746 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Tue, 2 Aug 2016 22:17:05 -0400 Subject: [PATCH 192/204] Send the appendix to nostarch too. --- nostarch/appendix.md | 63 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 nostarch/appendix.md diff --git a/nostarch/appendix.md b/nostarch/appendix.md new file mode 100644 index 0000000000..6f061d779b --- /dev/null +++ b/nostarch/appendix.md @@ -0,0 +1,63 @@ +# Appendix + +The following sections contain reference material you may find useful in your +Rust journey. + +## Keywords + +The following keywords are reserved by the Rust language and may not be used as +names of functions, variables, macros, modules, crates, constants, static +values, attributes, struct fields, or arguments. + +* `abstract` +* `alignof` +* `as` +* `become` +* `box` +* `break` +* `const` +* `continue` +* `crate` +* `do` +* `else` +* `enum` +* `extern` +* `false` +* `final` +* `fn` +* `for` +* `if` +* `impl` +* `in` +* `let` +* `loop` +* `macro` +* `match` +* `mod` +* `move` +* `mut` +* `offsetof` +* `override` +* `priv` +* `proc` +* `pub` +* `pure` +* `ref` +* `return` +* `Self` +* `self` +* `sizeof` +* `static` +* `struct` +* `super` +* `trait` +* `true` +* `type` +* `typeof` +* `unsafe` +* `unsized` +* `use` +* `virtual` +* `where` +* `while` +* `yield` From ab33390ead01efbf207540323f367b513ac0b0ae Mon Sep 17 00:00:00 2001 From: Alfie John <33c6c91f3bb4a391082e8a29642cafaf@alfie.wtf> Date: Wed, 3 Aug 2016 10:11:30 +0000 Subject: [PATCH 193/204] Removed duplicate "the" --- src/ch03-05-control-flow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ch03-05-control-flow.md b/src/ch03-05-control-flow.md index 500050ca1c..9fe780eb45 100644 --- a/src/ch03-05-control-flow.md +++ b/src/ch03-05-control-flow.md @@ -377,7 +377,7 @@ and missing some items. For example, in the previous code that uses the `while` loop, if we removed an item from the `a` array but forgot to update the condition to be `while index < 4`, our code would panic. Using the `for` loop means we would not need to -remember to change any other code if we changed the the number of values in the +remember to change any other code if we changed the number of values in the array. If you're wondering about the `.iter()` code in this example, keep reading! We From 08194ba20d222d350056b262ef7371aef77d8ab9 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 6 Aug 2016 14:02:36 -0400 Subject: [PATCH 194/204] Have travis print the version of mdbook that gets installed --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e740ab8fc2..ce1c3d5b68 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ rust: - stable before_script: - cargo install mdbook + - PATH=$PATH:/home/travis/.cargo/bin mdbook --version script: - PATH=$PATH:/home/travis/.cargo/bin mdbook test - PATH=$PATH:/home/travis/.cargo/bin mdbook build From 8890e8a228031e9f17f25cb5b0405b32dc6aac0f Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 6 Aug 2016 14:07:48 -0400 Subject: [PATCH 195/204] Revert "Have travis print the version of mdbook that gets installed" This reverts commit 08194ba20d222d350056b262ef7371aef77d8ab9. Nevermind, this doesn't do what I want and I see now how to expand the output on travis to see the version of mdbook. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ce1c3d5b68..e740ab8fc2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,6 @@ rust: - stable before_script: - cargo install mdbook - - PATH=$PATH:/home/travis/.cargo/bin mdbook --version script: - PATH=$PATH:/home/travis/.cargo/bin mdbook test - PATH=$PATH:/home/travis/.cargo/bin mdbook build From b331986493de48b744d21096077c2f4a5420531f Mon Sep 17 00:00:00 2001 From: "Eric D. Reichert" Date: Sat, 6 Aug 2016 21:27:15 -0400 Subject: [PATCH 196/204] Added initial file path linter. --- .gitignore | 3 + Cargo.lock | 140 ++++++++++++++++++++++++++++ Cargo.toml | 10 ++ src/bin/lfp.rs | 246 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 399 insertions(+) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/bin/lfp.rs diff --git a/.gitignore b/.gitignore index bac8a05a0a..1b3250eb8c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ book/ *~ +.idea +.DS_Store +target \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000..4dc998bf68 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,140 @@ +[root] +name = "rust-book" +version = "0.0.1" +dependencies = [ + "docopt 0.6.82 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "aho-corasick" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "docopt" +version = "0.6.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "0.1.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc-serialize" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "strsim" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "thread-id" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "utf8-ranges" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9" +"checksum docopt 0.6.82 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20016093b4e545dccf6ad4a01099de0b695f9bc99b08210e68f6425db2d37d" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f" +"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2" +"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" +"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2" +"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199" +"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b" +"checksum strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4d73a2c36a4d095ed1a6df5cbeac159863173447f7a82b3f4757426844ab825" +"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" +"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d" +"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" +"checksum walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad450634b9022aeb0e8e7f1c79c1ded92d0fc5bee831033d148479771bd218d" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000..7c0ab66389 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rust-book" +version = "0.0.1" +authors = ["Steve Klabnik "] +description = "The Rust Book" + +[dependencies] +walkdir = "0.1.5" +docopt = "0.6.82" +rustc-serialize = "0.3.19" \ No newline at end of file diff --git a/src/bin/lfp.rs b/src/bin/lfp.rs new file mode 100644 index 0000000000..d7aed1c772 --- /dev/null +++ b/src/bin/lfp.rs @@ -0,0 +1,246 @@ +extern crate rustc_serialize; +extern crate docopt; +use docopt::Docopt; +extern crate walkdir; +use std::{path, fs, io}; +use std::io::{BufRead, Write}; + +macro_rules! println_stderr( + ($($arg:tt)*) => ( + match writeln!(&mut ::std::io::stderr(), $($arg)* ) { + Ok(_) => {}, + Err(x) => panic!("Unable to write to stderr: {}", x), + } + ) +); + +fn main () { + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.decode()) + .unwrap_or_else(|e| e.exit()); + + let src_dir = &path::Path::new(&args.arg_src_dir); + let found_errs = walkdir::WalkDir::new(src_dir) + .min_depth(1) + .into_iter() + .map(|entry| { + match entry { + Ok(entry) => entry, + Err(err) => { + println_stderr!("{:?}", err); + std::process::exit(911) + }, + } + }) + .map(|entry| { + let path = entry.path(); + if is_file_of_interest(path) { + let err_vec = lint_file(path); + for err in &err_vec { + match *err { + LintingError::LineOfInterest(line_num, ref line) => + println_stderr!("{}:{}\t{}", path.display(), line_num, line), + LintingError::UnableToOpenFile => + println_stderr!("Unable to open {}.", path.display()), + } + } + !err_vec.is_empty() + } else { + false + } + }) + .collect::>() + .iter() + .any(|result| *result); + + if found_errs { + std::process::exit(1) + } else { + std::process::exit(0) + } +} + +const USAGE: &'static str = " +counter +Usage: + lfp + lfp (-h | --help) +Options: + -h --help Show this screen. +"; + +#[derive(Debug, RustcDecodable)] +struct Args { + arg_src_dir: String, +} + +fn lint_file(path: &path::Path) -> Vec { + match fs::File::open(path) { + Ok(file) => lint_lines(io::BufReader::new(&file).lines()), + Err(_) => vec![LintingError::UnableToOpenFile], + } +} + +fn lint_lines(lines: I) -> Vec + where I: Iterator> { + lines + .enumerate() + .map(|(line_num, line)| { + let raw_line = line.unwrap(); + if is_line_of_interest(&raw_line) { + Err(LintingError::LineOfInterest(line_num, raw_line)) + } else { + Ok(()) + } + }) + .filter(|result| result.is_err()) + .map(|result| result.unwrap_err()) + .collect() +} + +fn is_file_of_interest(path: &path::Path) -> bool { + path.extension() + .map_or(false, |ext| ext == "md") +} + +fn is_line_of_interest(line: &str) -> bool { + !line.split_whitespace() + .filter(|sub_string| sub_string.contains("file://")) + .filter(|file_url| !file_url.contains("file:///projects/")) + .collect::>() + .is_empty() +} + +#[derive(Debug)] +enum LintingError { + UnableToOpenFile, + LineOfInterest(usize, String) +} + +#[cfg(test)] +mod tests { + + use std::path; + + #[test] + fn lint_file_returns_a_vec_with_errs_when_lines_of_interest_are_found() { + let string = r#" + $ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/guessing_game` + Guess the number! + The secret number is: 61 + Please input your guess. + 10 + You guessed: 10 + Too small! + Please input your guess. + 99 + You guessed: 99 + Too big! + Please input your guess. + foo + Please input your guess. + 61 + You guessed: 61 + You win! + $ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/debug/guessing_game` + Guess the number! + The secret number is: 7 + Please input your guess. + 4 + You guessed: 4 + $ cargo run + Running `target/debug/guessing_game` + Guess the number! + The secret number is: 83 + Please input your guess. + 5 + $ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/debug/guessing_game` + Hello, world! + "#; + + let raw_lines = string.to_string(); + let lines = raw_lines.lines().map(|line| { + Ok(line.to_string()) + }); + + let result_vec = super::lint_lines(lines); + + assert!(!result_vec.is_empty()); + assert_eq!(3, result_vec.len()); + } + + #[test] + fn lint_file_returns_an_empty_vec_when_no_lines_of_interest_are_found() { + let string = r#" + $ cargo run + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) + Running `target/guessing_game` + Guess the number! + The secret number is: 61 + Please input your guess. + 10 + You guessed: 10 + Too small! + Please input your guess. + 99 + You guessed: 99 + Too big! + Please input your guess. + foo + Please input your guess. + 61 + You guessed: 61 + You win! + "#; + + let raw_lines = string.to_string(); + let lines = raw_lines.lines().map(|line| { + Ok(line.to_string()) + }); + + let result_vec = super::lint_lines(lines); + + assert!(result_vec.is_empty()); + } + + #[test] + fn is_file_of_interest_returns_false_when_the_path_is_a_directory() { + let uninteresting_fn = "src/img"; + + assert!(!super::is_file_of_interest(path::Path::new(uninteresting_fn))); + } + + #[test] + fn is_file_of_interest_returns_false_when_the_filename_does_not_have_the_md_extension() { + let uninteresting_fn = "src/img/foo1.png"; + + assert!(!super::is_file_of_interest(path::Path::new(uninteresting_fn))); + } + + #[test] + fn is_file_of_interest_returns_true_when_the_filename_has_the_md_extension() { + let interesting_fn = "src/ch01-00-introduction.md"; + + assert!(super::is_file_of_interest(path::Path::new(interesting_fn))); + } + + #[test] + fn is_line_of_interest_does_not_report_a_line_if_the_line_contains_a_file_url_which_is_directly_followed_by_the_project_path() { + let sample_line = "Compiling guessing_game v0.1.0 (file:///projects/guessing_game)"; + + assert!(!super::is_line_of_interest(sample_line)); + } + + #[test] + fn is_line_of_interest_reports_a_line_if_the_line_contains_a_file_url_which_is_not_directly_followed_by_the_project_path() { + let sample_line = "Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)"; + + assert!(super::is_line_of_interest(sample_line)); + } +} \ No newline at end of file From 86cb7f043a038e3340f036be6aecf1e48cf7c444 Mon Sep 17 00:00:00 2001 From: "Eric D. Reichert" Date: Mon, 8 Aug 2016 21:24:17 -0400 Subject: [PATCH 197/204] Got rid of one of the filters when checking for a line of interest. --- src/bin/lfp.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bin/lfp.rs b/src/bin/lfp.rs index d7aed1c772..1ac399c061 100644 --- a/src/bin/lfp.rs +++ b/src/bin/lfp.rs @@ -105,8 +105,7 @@ fn is_file_of_interest(path: &path::Path) -> bool { fn is_line_of_interest(line: &str) -> bool { !line.split_whitespace() - .filter(|sub_string| sub_string.contains("file://")) - .filter(|file_url| !file_url.contains("file:///projects/")) + .filter(|sub_string| sub_string.contains("file://") && !sub_string.contains("file:///projects/")) .collect::>() .is_empty() } From 106604eb7908fb680df1a8fe3c63902f6543fb58 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 10 Aug 2016 18:54:11 -0400 Subject: [PATCH 198/204] Introduce byte literal syntax so we can use it later --- src/ch03-02-data-types.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/ch03-02-data-types.md b/src/ch03-02-data-types.md index 9025a9f842..5cd2d38996 100644 --- a/src/ch03-02-data-types.md +++ b/src/ch03-02-data-types.md @@ -160,6 +160,22 @@ about Unicode Scalar Values at *http://www.unicode.org/glossary/#unicode_scalar_value* and find a chart for all unicode code points at *http://www.unicode.org/charts/*. +#### The Byte Type + +You can work with the bytes of data directly. Byte literals can be created from +the ASCII characters using `b` and single quotes: + +```rust +fn main() { + let byte = b' '; + println!("byte is {}", byte); +} +``` + +This will print `byte is 97`. Similarly, byte string literals can be created +using `b` and double quotes, like `b"some byte string"`. Note that since you are +limited to ASCII characters, it's a best practice to use characters instead of bytes when you're working with natural language text. + ### Compound Types *Compound types* can group multiple values of other types into one type. Rust From 7eb505d7a0e7c61c283ce1d46f7f24fad9bd35f7 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 10 Aug 2016 19:14:25 -0400 Subject: [PATCH 199/204] Add newlines to the ends of files --- .gitignore | 3 ++- Cargo.toml | 2 +- src/bin/lfp.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 1b3250eb8c..7851fa00e8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ book/ *~ .idea .DS_Store -target \ No newline at end of file +target + diff --git a/Cargo.toml b/Cargo.toml index 7c0ab66389..b1a45033ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,4 @@ description = "The Rust Book" [dependencies] walkdir = "0.1.5" docopt = "0.6.82" -rustc-serialize = "0.3.19" \ No newline at end of file +rustc-serialize = "0.3.19" diff --git a/src/bin/lfp.rs b/src/bin/lfp.rs index 1ac399c061..7b5bce2a69 100644 --- a/src/bin/lfp.rs +++ b/src/bin/lfp.rs @@ -242,4 +242,4 @@ mod tests { assert!(super::is_line_of_interest(sample_line)); } -} \ No newline at end of file +} From dd9621ce8bc1de5d29c23d0642c45cc059748a63 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 10 Aug 2016 19:18:30 -0400 Subject: [PATCH 200/204] Hook lints into travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e740ab8fc2..cf7d26ca9a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ before_script: script: - PATH=$PATH:/home/travis/.cargo/bin mdbook test - PATH=$PATH:/home/travis/.cargo/bin mdbook build + - cargo run --bin lfp src after_success: - test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && bash deploy.sh env: From 52db720fc18a447a48e8b720304f674133f143c7 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 10 Aug 2016 19:26:07 -0400 Subject: [PATCH 201/204] Make all the cargo output say file:///projects/... that the lint found! --- src/ch01-02-hello-world.md | 4 ++-- src/ch02-00-guessing-game-tutorial.md | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ch01-02-hello-world.md b/src/ch01-02-hello-world.md index f7d1bf4399..fd9799e2f9 100644 --- a/src/ch01-02-hello-world.md +++ b/src/ch01-02-hello-world.md @@ -284,7 +284,7 @@ program through Cargo! To do so, enter the following commands: ```bash $ cargo build - Compiling hello_cargo v0.1.0 (file:///home/yourname/projects/hello_cargo) + Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo) ``` This should have created an executable file in `target/debug/hello_cargo` (or `target/debug/hello_cargo.exe` on Windows), which you can run with this command: @@ -327,7 +327,7 @@ project before running it, and you would have seen something like this: ```bash $ cargo run - Compiling hello_cargo v0.1.0 (file:///home/yourname/projects/hello_cargo) + Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo) Running `target/debug/hello_cargo` Hello, world! ``` diff --git a/src/ch02-00-guessing-game-tutorial.md b/src/ch02-00-guessing-game-tutorial.md index 0deffef99e..8bf2331ffa 100644 --- a/src/ch02-00-guessing-game-tutorial.md +++ b/src/ch02-00-guessing-game-tutorial.md @@ -46,7 +46,7 @@ Let’s try compiling what Cargo gave us and running it in the same step, using ```bash $ cargo run - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Running `target/debug/guessing_game` Hello, world! ``` @@ -251,7 +251,7 @@ If we don't call this method, our program will compile, but we’ll get a warnin ```bash $ cargo build - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) src/main.rs:10:5: 10:39 warning: unused result which must be used, #[warn(unused_must_use)] on by default src/main.rs:10 io::stdin().read_line(&mut guess); @@ -293,7 +293,7 @@ Anyway, back to our guessing game. We can run what we have with `cargo run`: ```bash $ cargo run - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Running `target/debug/guessing_game` Guess the number! Please input your guess. @@ -347,7 +347,7 @@ $ cargo build Downloading libc v0.2.14 Compiling libc v0.2.14 Compiling rand v0.3.14 - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) ``` You may see different versions (but they will be compatible, thanks to semver!) @@ -380,7 +380,7 @@ we’ll only see one line: ```bash $ cargo build - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) ``` What happens when next week version `v0.3.15` of the `rand` crate comes out, @@ -478,7 +478,7 @@ Try running our new program a few times: ```bash $ cargo run - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Running `target/debug/guessing_game` Guess the number! The secret number is: 7 @@ -588,7 +588,7 @@ We did mention that this won’t quite compile yet, though. Let’s try it: ```bash $ cargo build - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) src/main.rs:23:21: 23:35 error: mismatched types [E0308] src/main.rs:23 match guess.cmp(&secret_number) { ^~~~~~~~~~~~~~ @@ -694,7 +694,7 @@ Let’s try our program out! ```bash $ cargo run - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Running `target/guessing_game` Guess the number! The secret number is: 58 @@ -757,7 +757,7 @@ will crash and, therefore, quit. Observe: ```bash $ cargo run - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Running `target/guessing_game` Guess the number! The secret number is: 59 @@ -894,7 +894,7 @@ Now we should be good! Let’s try it: ```bash $ cargo run - Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) Running `target/guessing_game` Guess the number! The secret number is: 61 From 514017dbac97074beb04ddf487cc3fa4c3f1226c Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 10 Aug 2016 19:30:49 -0400 Subject: [PATCH 202/204] Add the travis build image to the readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c2355fdefd..c2c3c57870 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # The Rust Programming Language +[![Build Status](https://travis-ci.org/rust-lang/book.svg?branch=master)](https://travis-ci.org/rust-lang/book) + This is the next iteration of “The Rust Programming Language”, which is currently located [in the main Rust repository][src]. If you want to read the book, you should check it out there or [on the web][prod]. From 37575e7b2191ca6aa95d21af2d8381a51f20c96b Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 10 Aug 2016 19:33:21 -0400 Subject: [PATCH 203/204] Install mdbook from git to get the exit status fix --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cf7d26ca9a..20feeecd8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ rust: - beta - stable before_script: - - cargo install mdbook + - cargo install mdbook --git https://github.com/azerupi/mdBook.git script: - PATH=$PATH:/home/travis/.cargo/bin mdbook test - PATH=$PATH:/home/travis/.cargo/bin mdbook build From 85fd039271bba5056d61e04529bead7048b9e93c Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 10 Aug 2016 19:46:32 -0400 Subject: [PATCH 204/204] Fix the merge I messed up --- src/ch04-03-slices.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index 044c029d16..cbda81644a 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -25,7 +25,7 @@ fn first_word(s: &String) -> usize { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { - if byte == b' ' { + if item == b' ' { return i; } } @@ -81,7 +81,7 @@ that it will still be valid in the future. Consider this: # let bytes = s.as_bytes(); # # for (i, &item) in bytes.iter().enumerate() { -# if byte == b' ' { +# if item == b' ' { # return i; # } # } @@ -181,7 +181,7 @@ fn first_word(s: &String) -> &str { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { - if byte == b' ' { + if item == b' ' { return &s[0..i]; } } @@ -279,7 +279,7 @@ with no loss of functionality: # let bytes = s.as_bytes(); # # for (i, &item) in bytes.iter().enumerate() { -# if byte == b' ' { +# if item == b' ' { # return &s[0..i]; # } # }