From b51c08a44a123a52620f20c45a4ecb534e556b22 Mon Sep 17 00:00:00 2001 From: funkill2 Date: Wed, 16 Oct 2024 04:00:15 +0300 Subject: [PATCH] update original --- rustbook-en/nostarch/chapter17.md | 69 +++++++----- .../packages/mdbook-trpl-listing/src/lib.rs | 21 ++-- .../mdbook-trpl-listing/src/tests/mod.rs | 103 ++++++++++++++++++ rustbook-en/src/ch06-01-defining-an-enum.md | 10 +- rustbook-en/src/ch06-02-match.md | 15 ++- rustbook-en/src/ch06-03-if-let.md | 5 +- ...ng-modules-to-control-scope-and-privacy.md | 18 +-- ...referring-to-an-item-in-the-module-tree.md | 41 +++---- ...g-paths-into-scope-with-the-use-keyword.md | 58 +++++----- ...separating-modules-into-different-files.md | 18 +-- rustbook-en/src/ch08-01-vectors.md | 50 +++++---- rustbook-en/src/ch08-02-strings.md | 44 +++++--- rustbook-en/src/ch08-03-hash-maps.md | 30 +++-- ...ch09-01-unrecoverable-errors-with-panic.md | 14 ++- .../ch09-02-recoverable-errors-with-result.md | 57 +++++----- .../src/ch09-03-to-panic-or-not-to-panic.md | 9 +- rustbook-en/src/ch10-00-generics.md | 15 +-- rustbook-en/src/ch10-01-syntax.md | 45 ++++---- rustbook-en/src/ch10-02-traits.md | 20 ++-- rustbook-en/src/ch10-03-lifetime-syntax.md | 61 +++++------ rustbook-en/src/ch15-01-box.md | 25 ++--- rustbook-en/src/ch15-02-deref.md | 38 +++---- rustbook-en/src/ch15-03-drop.md | 15 +-- rustbook-en/src/ch15-04-rc.md | 14 +-- .../src/ch15-05-interior-mutability.md | 25 ++--- rustbook-en/src/ch15-06-reference-cycles.md | 25 ++--- rustbook-en/src/ch16-01-threads.md | 30 +++-- rustbook-en/src/ch16-02-message-passing.md | 25 ++--- rustbook-en/src/ch16-03-shared-state.md | 20 ++-- rustbook-en/src/ch17-03-more-futures.md | 8 +- rustbook-en/src/ch17-04-streams.md | 2 +- rustbook-en/src/ch17-05-traits-for-async.md | 50 ++++++--- .../src/ch17-06-futures-tasks-threads.md | 4 +- rustbook-en/src/ch18-01-what-is-oo.md | 6 +- rustbook-en/src/ch18-03-oo-design-patterns.md | 2 +- 35 files changed, 550 insertions(+), 442 deletions(-) diff --git a/rustbook-en/nostarch/chapter17.md b/rustbook-en/nostarch/chapter17.md index af8698283..225b0a8a4 100644 --- a/rustbook-en/nostarch/chapter17.md +++ b/rustbook-en/nostarch/chapter17.md @@ -1669,10 +1669,10 @@ The version with `yield_now` is *way* faster! This means that async can be useful even for compute-bound tasks, depending on what else your program is doing, because it provides a useful tool for structuring the relationships between different parts of the program. This is a -form of *cooperative multitasking*, where each future has both the power to -determine when it hands over control via await points. Each future therefore -also has the responsibility to avoid blocking for too long. In some Rust-based -embedded operating systems, this is the *only* kind of multitasking! +form of *cooperative multitasking*, where each future has the power to determine +when it hands over control via await points. Each future therefore also has the +responsibility to avoid blocking for too long. In some Rust-based embedded +operating systems, this is the *only* kind of multitasking! In real-world code, you won’t usually be alternating function calls with await points on every single line, of course. While yielding control in this way is @@ -2046,7 +2046,7 @@ indicates a message arrived in time; the `Err` variant indicates that the timeout elapsed before any message arrived. We `match` on that result and either print the message when we receive it successfully, or print a notice about the timeout. Finally, notice that we pin the messages after applying the timeout to -them, because the timeout helper produces a future which needs to be pinned to +them, because the timeout helper produces a stream which needs to be pinned to be polled. Filename: src/main.rs @@ -2507,7 +2507,7 @@ it is not yet ready. ### Pinning and the Pin and Unpin Traits -When we introduced the idea of pinning, while working on Listing 17-17, we ran +When we introduced the idea of pinning while working on Listing 17-17, we ran into a very gnarly error message. Here is the relevant part of it again: ``` @@ -2535,12 +2535,20 @@ For more information about an error, try `rustc --explain E0277`. When we read this error message carefully, it not only tells us that we need to pin the values, but also tells us why pinning is required. The `trpl::join_all` -function returns a struct called `JoinAll`. That struct, in turn, is generic -over a type `F`, which is constrained to implement the `Future` trait. Finally, -directly awaiting a Future requires that the future in question implement the -`Unpin` trait. That’s a lot! But we can understand it, if we dive a little -further into how the `Future` type actually works, in particular around -*pinning*. +function returns a struct called `JoinAll`. That struct is generic over a type +`F`, which is constrained to implement the `Future` trait. Directly awaiting a +future with `await` pins the future implicitly. That’s why we don’t need to use +`pin!` everywhere we want to await futures. + +However, we’re not directly awaiting a future here. Instead, we construct a new +future, `JoinAll`, by passing a collection of futures to the `join_all` +function. The signature for `join_all` produces requires that the type of the +items in the collection all implement the `Future` trait, and `Box` only +implements `Future` if the `T` that it wraps is a future which implements the +`Unpin` trait. + +That’s a lot! But we can understand it, if we dive a little further into how the +`Future` type actually works, in particular around *pinning*. Let’s look again at the definition of `Future`: @@ -2684,24 +2692,32 @@ that a given type does *not* need to uphold any particular guarantees about whether the value in question can be moved. Just as with `Send` and `Sync`, the compiler implements `Unpin` automatically -for all types where it can prove it is safe. Implementing `Unpin` manually is -unsafe because it requires *you* to uphold all the guarantees which make `Pin` -and `Unpin` safe yourself for a type with internal references. In practice, -this is a very rare thing to implement yourself! +for all types where it can prove it is safe. The special case, again similar to +`Send` and `Sync`, is the case where `Unpin` is *not* implemented for a type. +The notation for this is `impl !Unpin for SomeType`, where `SomeType` is the +name of a type which *does* need to uphold those guarantees to be safe whenever +a pointer to that type it is used in a `Pin`. + +In other words, there are two things to keep in mind about the relationship +between `Pin` and `Unpin`. First, `Unpin` is the “normal” case, and `!Unpin` is +the special case. Second, whether a type implements `Unpin` or `!Unpin` *only* +matters when using a pinned pointer to that type like `Pin<&mut SomeType>`. To make that concrete, think about a `String`: it has a length and the Unicode characters which make it up. We can wrap a `String` in `Pin`, as seen in Figure -17-7. However +17-8. However, `String` automatically implements `Unpin`, the same as most other +types in Rust. Concurrent work flow Figure 17-8: Pinning a String, with a dotted line indicating that the String implements the `Unpin` trait, so it is not pinned. -This means that we can do things such as replace one string with another at the -exact same location in memory as in Figure 17-9. This doesn’t violate the `Pin` -contract because `String`—like most other types in Rust—implements `Unpin`, -because it has no internal references that make it unsafe to move around! +As a result, we can do things which would be illegal if `String` implemented +`!Unpin` instead, such as replace one string with another at the exact same +location in memory as in Figure 17-9. This doesn’t violate the `Pin` contract, +because `String` has no internal references that make it unsafe to move around! +That is precisely why it implements `Unpin` rather than `!Unpin`. Concurrent work flow @@ -2710,9 +2726,10 @@ Figure 17-9: Replacing the String with an entirely different String in memory. Now we know enough to understand the errors reported for that `join_all` call from back in Listing 17-17. We originally tried to move the futures produced by async blocks into a `Vec>>`, but as we’ve seen, -those futures may have internal references, so they don’t implement `Unpin`. -They need to be pinned, and then we can pass the `Pin` type into the `Vec`, -confident that the underlying data in the futures will *not* be moved. +those futures may have internal references, so they don’t automatically +implement `Unpin`. Once we pin them, we can pass the resulting `Pin` type into +the `Vec`, confident that the underlying data in the futures will *not* be +moved. `Pin` and `Unpin` are mostly important for building lower-level libraries, or when you’re building a runtime itself, rather than for day to day Rust code. @@ -2943,9 +2960,9 @@ threads *and* tasks, and therefore futures. As a default way of thinking about which to use when: -* If the task is *very parallelizable*, such as processing a bunch of data where +* If the work is *very parallelizable*, such as processing a bunch of data where each part can be processed separately, threads are a better choice. -* If the task is *very concurrent*, such as handling messages from a bunch of +* If the work is *very concurrent*, such as handling messages from a bunch of different sources which may come in a different intervals or different rates, async is a better choice. diff --git a/rustbook-en/packages/mdbook-trpl-listing/src/lib.rs b/rustbook-en/packages/mdbook-trpl-listing/src/lib.rs index 619cafdf3..c4ff14e44 100644 --- a/rustbook-en/packages/mdbook-trpl-listing/src/lib.rs +++ b/rustbook-en/packages/mdbook-trpl-listing/src/lib.rs @@ -195,7 +195,7 @@ impl<'e> ListingState<'e> { ) -> Result<(), String> { // We do not *keep* the version constructed here, just temporarily // construct it so the HTML parser, which expects properly closed tags - // to parse it as a *tag* rather than a *weird text node*, which accept + // to parse it as a *tag* rather than a *weird text node*, will accept // it and provide a useful view of it. let to_parse = tag.to_owned().to_string() + ""; let listing = Dom::parse(&to_parse) @@ -212,21 +212,22 @@ impl<'e> ListingState<'e> { .try_fold(ListingBuilder::new(), |builder, (key, maybe_value)| { match (key.as_str(), maybe_value) { ("number", Some(value)) => Ok(builder.with_number(value)), - ("number", None) => { - Err(String::from("number attribute without value")) - } + ("caption", Some(value)) => Ok(builder.with_caption(value)), - ("caption", None) => { - Err(String::from("caption attribute without value")) - } + ("file-name", Some(value)) => { Ok(builder.with_file_name(value)) } - ("file-name", None) => { - Err(String::from("file-name attribute without value")) + + (attr @ "file-name", None) + | (attr @ "caption", None) + | (attr @ "number", None) => { + Err(format!("Missing value for attribute: '{attr}'")) } - _ => Ok(builder), // TODO: error on extra attrs? + (attr, _) => { + Err(format!("Unsupported attribute name: '{attr}'")) + } } })? .build(); diff --git a/rustbook-en/packages/mdbook-trpl-listing/src/tests/mod.rs b/rustbook-en/packages/mdbook-trpl-listing/src/tests/mod.rs index 5ae5c8e96..224b14fe5 100644 --- a/rustbook-en/packages/mdbook-trpl-listing/src/tests/mod.rs +++ b/rustbook-en/packages/mdbook-trpl-listing/src/tests/mod.rs @@ -188,5 +188,108 @@ fn main() {} ); } +#[test] +fn with_unsupported_attr_name() { + let result = rewrite_listing( + "+ +```rust +fn main() {} +``` + +", + Mode::Default, + ); + + assert_eq!( + result, + Err(String::from("Unsupported attribute name: 'invalid-attr'")) + ) +} + +#[test] +fn with_unsupported_attr_name_with_arg() { + let result = rewrite_listing( + r#"+ +```rust +fn main() {} +``` + +"#, + Mode::Default, + ); + + assert_eq!( + result, + Err(String::from("Unsupported attribute name: 'invalid-attr'")) + ) +} + +#[cfg(test)] +mod missing_value { + use super::*; + + #[test] + fn for_number() { + let result = rewrite_listing( + r#"+ +```rust +fn main() {} +``` + +"#, + Mode::Default, + ); + + assert_eq!( + result, + Err(String::from("Missing value for attribute: 'number'")) + ) + } + + #[test] + fn for_caption() { + let result = rewrite_listing( + r#"+ +```rust +fn main() {} +``` + +"#, + Mode::Default, + ); + + assert_eq!( + result, + Err(String::from("Missing value for attribute: 'caption'")) + ) + } + + #[test] + fn for_file_name() { + let result = rewrite_listing( + r#"+ +```rust +fn main() {} +``` + +"#, + Mode::Default, + ); + + assert_eq!( + result, + Err(String::from("Missing value for attribute: 'file-name'")) + ) + } +} + +#[test] +fn missing_value() {} + #[cfg(test)] mod config; diff --git a/rustbook-en/src/ch06-01-defining-an-enum.md b/rustbook-en/src/ch06-01-defining-an-enum.md index eacd091bd..3462f3891 100644 --- a/rustbook-en/src/ch06-01-defining-an-enum.md +++ b/rustbook-en/src/ch06-01-defining-an-enum.md @@ -59,12 +59,13 @@ only know what *kind* it is. Given that you just learned about structs in Chapter 5, you might be tempted to tackle this problem with structs as shown in Listing 6-1. ++ ```rust {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-01/src/main.rs:here}} ``` -Listing 6-1: Storing the data and `IpAddrKind` variant of -an IP address using a `struct` + Here, we’ve defined a struct `IpAddr` that has two fields: a `kind` field that is of type `IpAddrKind` (the enum we defined previously) and an `address` field @@ -140,12 +141,13 @@ more about bringing types into scope in Chapter 7. Let’s look at another example of an enum in Listing 6-2: this one has a wide variety of types embedded in its variants. ++ ```rust {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-02/src/main.rs:here}} ``` -Listing 6-2: A `Message` enum whose variants each store -different amounts and types of values + This enum has four variants with different types: diff --git a/rustbook-en/src/ch06-02-match.md b/rustbook-en/src/ch06-02-match.md index eec1ac4a8..f81907c9e 100644 --- a/rustbook-en/src/ch06-02-match.md +++ b/rustbook-en/src/ch06-02-match.md @@ -22,12 +22,13 @@ function that takes an unknown US coin and, in a similar way as the counting machine, determines which coin it is and returns its value in cents, as shown in Listing 6-3. ++ ```rust {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-03/src/main.rs:here}} ``` -Listing 6-3: An enum and a `match` expression that has -the variants of the enum as its patterns + Let’s break down the `match` in the `value_in_cents` function. First we list the `match` keyword followed by an expression, which in this case is the value @@ -75,12 +76,13 @@ designs, so only quarters have this extra value. We can add this information to our `enum` by changing the `Quarter` variant to include a `UsState` value stored inside it, which we’ve done in Listing 6-4. ++ ```rust {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-04/src/main.rs:here}} ``` -Listing 6-4: A `Coin` enum in which the `Quarter` variant -also holds a `UsState` value + Let’s imagine that a friend is trying to collect all 50 state quarters. While we sort our loose change by coin type, we’ll also call out the name of the @@ -119,12 +121,13 @@ operations. This function is very easy to write, thanks to `match`, and will look like Listing 6-5. ++ ```rust {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:here}} ``` -Listing 6-5: A function that uses a `match` expression on -an `Option` + Let’s examine the first execution of `plus_one` in more detail. When we call `plus_one(five)`, the variable `x` in the body of `plus_one` will have the diff --git a/rustbook-en/src/ch06-03-if-let.md b/rustbook-en/src/ch06-03-if-let.md index c9bfbf3c7..fee6b2caf 100644 --- a/rustbook-en/src/ch06-03-if-let.md +++ b/rustbook-en/src/ch06-03-if-let.md @@ -6,12 +6,13 @@ program in Listing 6-6 that matches on an `Option` value in the `config_max` variable but only wants to execute code if the value is the `Some` variant. ++ ```rust {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-06/src/main.rs:here}} ``` -Listing 6-6: A `match` that only cares about executing -code when the value is `Some` + If the value is `Some`, we print out the value in the `Some` variant by binding the value to the variable `max` in the pattern. We don’t want to do anything diff --git a/rustbook-en/src/ch07-02-defining-modules-to-control-scope-and-privacy.md b/rustbook-en/src/ch07-02-defining-modules-to-control-scope-and-privacy.md index 4a25c161b..c1afe4c15 100644 --- a/rustbook-en/src/ch07-02-defining-modules-to-control-scope-and-privacy.md +++ b/rustbook-en/src/ch07-02-defining-modules-to-control-scope-and-privacy.md @@ -63,21 +63,25 @@ backyard The crate root file in this case is *src/main.rs*, and it contains: -Filename: src/main.rs + ```rust,noplayground,ignore {{#rustdoc_include ../listings/ch07-managing-growing-projects/quick-reference-example/src/main.rs}} ``` + + The `pub mod garden;` line tells the compiler to include the code it finds in *src/garden.rs*, which is: -Filename: src/garden.rs + ```rust,noplayground,ignore {{#rustdoc_include ../listings/ch07-managing-growing-projects/quick-reference-example/src/garden.rs}} ``` + + Here, `pub mod vegetables;` means the code in *src/garden/vegetables.rs* is included too. That code is: @@ -114,14 +118,13 @@ restaurant --lib`. Then enter the code in Listing 7-1 into *src/lib.rs* to define some modules and function signatures; this code is the front of house section. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-01/src/lib.rs}} ``` -Listing 7-1: A `front_of_house` module containing other -modules that then contain functions + We define a module with the `mod` keyword followed by the name of the module (in this case, `front_of_house`). The body of the module then goes inside curly @@ -143,6 +146,8 @@ known as the *module tree*. Listing 7-2 shows the module tree for the structure in Listing 7-1. ++ ```text crate └── front_of_house @@ -155,8 +160,7 @@ crate └── take_payment ``` -Listing 7-2: The module tree for the code in Listing -7-1 + This tree shows how some of the modules nest inside other modules; for example, `hosting` nests inside `front_of_house`. The tree also shows that some modules diff --git a/rustbook-en/src/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md b/rustbook-en/src/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md index 4201ea3db..da07d9fd8 100644 --- a/rustbook-en/src/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md +++ b/rustbook-en/src/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md @@ -29,14 +29,13 @@ The `eat_at_restaurant` function is part of our library crate’s public API, so we mark it with the `pub` keyword. In the [“Exposing Paths with the `pub` Keyword”][pub] section, we’ll go into more detail about `pub`. -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-03/src/lib.rs}} ``` -Listing 7-3: Calling the `add_to_waitlist` function using -absolute and relative paths + The first time we call the `add_to_waitlist` function in `eat_at_restaurant`, we use an absolute path. The `add_to_waitlist` function is defined in the same @@ -70,12 +69,13 @@ each other. Let’s try to compile Listing 7-3 and find out why it won’t compile yet! The errors we get are shown in Listing 7-4. ++ ```console {{#include ../listings/ch07-managing-growing-projects/listing-07-03/output.txt}} ``` -Listing 7-4: Compiler errors from building the code in -Listing 7-3 + The error messages say that module `hosting` is private. In other words, we have the correct paths for the `hosting` module and the `add_to_waitlist` @@ -105,24 +105,24 @@ private. We want the `eat_at_restaurant` function in the parent module to have access to the `add_to_waitlist` function in the child module, so we mark the `hosting` module with the `pub` keyword, as shown in Listing 7-5. -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-05/src/lib.rs}} ``` -Listing 7-5: Declaring the `hosting` module as `pub` to -use it from `eat_at_restaurant` + Unfortunately, the code in Listing 7-5 still results in compiler errors, as shown in Listing 7-6. ++ ```console {{#include ../listings/ch07-managing-growing-projects/listing-07-05/output.txt}} ``` -Listing 7-6: Compiler errors from building the code in -Listing 7-5 + What happened? Adding the `pub` keyword in front of `mod hosting` makes the module public. With this change, if we can access `front_of_house`, we can @@ -140,15 +140,13 @@ modules. Let’s also make the `add_to_waitlist` function public by adding the `pub` keyword before its definition, as in Listing 7-7. -Filename: src/lib.rs + ```rust,noplayground,test_harness {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-07/src/lib.rs}} ``` -Listing 7-7: Adding the `pub` keyword to `mod hosting` -and `fn add_to_waitlist` lets us call the function from -`eat_at_restaurant` + Now the code will compile! To see why adding the `pub` keyword lets us use these paths in `eat_at_restaurant` with respect to the privacy rules, let’s look @@ -216,14 +214,13 @@ function `fix_incorrect_order` defined in the `back_of_house` module calls the function `deliver_order` defined in the parent module by specifying the path to `deliver_order`, starting with `super`. -Filename: src/lib.rs + ```rust,noplayground,test_harness {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-08/src/lib.rs}} ``` -Listing 7-8: Calling a function using a relative path -starting with `super` + The `fix_incorrect_order` function is in the `back_of_house` module, so we can use `super` to go to the parent module of `back_of_house`, which in this case @@ -247,14 +244,13 @@ comes with a meal, but the chef decides which fruit accompanies the meal based on what’s in season and in stock. The available fruit changes quickly, so customers can’t choose the fruit or even see which fruit they’ll get. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-09/src/lib.rs}} ``` -Listing 7-9: A struct with some public fields and some -private fields + Because the `toast` field in the `back_of_house::Breakfast` struct is public, in `eat_at_restaurant` we can write and read to the `toast` field using dot @@ -272,14 +268,13 @@ have such a function, we couldn’t create an instance of `Breakfast` in In contrast, if we make an enum public, all of its variants are then public. We only need the `pub` before the `enum` keyword, as shown in Listing 7-10. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-10/src/lib.rs}} ``` -Listing 7-10: Designating an enum as public makes all its -variants public + Because we made the `Appetizer` enum public, we can use the `Soup` and `Salad` variants in `eat_at_restaurant`. diff --git a/rustbook-en/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md b/rustbook-en/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md index defa950c6..aaf7713e9 100644 --- a/rustbook-en/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md +++ b/rustbook-en/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md @@ -12,14 +12,13 @@ scope of the `eat_at_restaurant` function so we only have to specify `hosting::add_to_waitlist` to call the `add_to_waitlist` function in `eat_at_restaurant`. -Filename: src/lib.rs + ```rust,noplayground,test_harness {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-11/src/lib.rs}} ``` -Listing 7-11: Bringing a module into scope with -`use` + Adding `use` and a path in a scope is similar to creating a symbolic link in the filesystem. By adding `use crate::front_of_house::hosting` in the crate @@ -32,14 +31,13 @@ Note that `use` only creates the shortcut for the particular scope in which the child module named `customer`, which is then a different scope than the `use` statement, so the function body won’t compile. -Filename: src/lib.rs + ```rust,noplayground,test_harness,does_not_compile,ignore {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-12/src/lib.rs}} ``` -Listing 7-12: A `use` statement only applies in the scope -it’s in + The compiler error shows that the shortcut no longer applies within the `customer` module: @@ -60,14 +58,13 @@ crate::front_of_house::hosting` and then called `hosting::add_to_waitlist` in `eat_at_restaurant`, rather than specifying the `use` path all the way out to the `add_to_waitlist` function to achieve the same result, as in Listing 7-13. -Filename: src/lib.rs + ```rust,noplayground,test_harness {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-13/src/lib.rs}} ``` -Listing 7-13: Bringing the `add_to_waitlist` function -into scope with `use`, which is unidiomatic + Although both Listing 7-11 and Listing 7-13 accomplish the same task, Listing 7-11 is the idiomatic way to bring a function into scope with `use`. Bringing @@ -82,14 +79,13 @@ it’s idiomatic to specify the full path. Listing 7-14 shows the idiomatic way to bring the standard library’s `HashMap` struct into the scope of a binary crate. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-14/src/main.rs}} ``` -Listing 7-14: Bringing `HashMap` into scope in an -idiomatic way + There’s no strong reason behind this idiom: it’s just the convention that has emerged, and folks have gotten used to reading and writing Rust code this way. @@ -99,14 +95,13 @@ into scope with `use` statements, because Rust doesn’t allow that. Listing 7-1 shows how to bring two `Result` types into scope that have the same name but different parent modules, and how to refer to them. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-15/src/lib.rs:here}} ``` -Listing 7-15: Bringing two types with the same name into -the same scope requires using their parent modules. + As you can see, using the parent modules distinguishes the two `Result` types. If instead we specified `use std::fmt::Result` and `use std::io::Result`, we’d @@ -120,14 +115,13 @@ into the same scope with `use`: after the path, we can specify `as` and a new local name, or *alias*, for the type. Listing 7-16 shows another way to write the code in Listing 7-15 by renaming one of the two `Result` types using `as`. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-16/src/lib.rs:here}} ``` -Listing 7-16: Renaming a type when it’s brought into -scope with the `as` keyword + In the second `use` statement, we chose the new name `IoResult` for the `std::io::Result` type, which won’t conflict with the `Result` from `std::fmt` @@ -146,14 +140,13 @@ their scope. Listing 7-17 shows the code in Listing 7-11 with `use` in the root module changed to `pub use`. -Filename: src/lib.rs + ```rust,noplayground,test_harness {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-17/src/lib.rs}} ``` -Listing 7-17: Making a name available for any code to use -from a new scope with `pub use` + Before this change, external code would have to call the `add_to_waitlist` function by using the path @@ -186,12 +179,14 @@ added this line to *Cargo.toml*: * ch14-03-cargo-workspaces.md --> -Filename: Cargo.toml + ```toml {{#include ../listings/ch02-guessing-game-tutorial/listing-02-02/Cargo.toml:9:}} ``` + + Adding `rand` as a dependency in *Cargo.toml* tells Cargo to download the `rand` package and any dependencies from [crates.io](https://crates.io/) and make `rand` available to our project. @@ -231,25 +226,26 @@ each item on its own line can take up a lot of vertical space in our files. For example, these two `use` statements we had in the guessing game in Listing 2-4 bring items from `std` into scope: -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/src/main.rs:here}} ``` + + Instead, we can use nested paths to bring the same items into scope in one line. We do this by specifying the common part of the path, followed by two colons, and then curly brackets around a list of the parts of the paths that differ, as shown in Listing 7-18. -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-18/src/main.rs:here}} ``` -Listing 7-18: Specifying a nested path to bring multiple -items with the same prefix into scope + In bigger programs, bringing many items into scope from the same crate or module using nested paths can reduce the number of separate `use` statements @@ -260,27 +256,25 @@ two `use` statements that share a subpath. For example, Listing 7-19 shows two `use` statements: one that brings `std::io` into scope and one that brings `std::io::Write` into scope. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-19/src/lib.rs}} ``` -Listing 7-19: Two `use` statements where one is a subpath -of the other + The common part of these two paths is `std::io`, and that’s the complete first path. To merge these two paths into one `use` statement, we can use `self` in the nested path, as shown in Listing 7-20. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-20/src/lib.rs}} ``` -Listing 7-20: Combining the paths in Listing 7-19 into -one `use` statement + This line brings `std::io` and `std::io::Write` into scope. diff --git a/rustbook-en/src/ch07-05-separating-modules-into-different-files.md b/rustbook-en/src/ch07-05-separating-modules-into-different-files.md index b4cbcdbed..2952e4b15 100644 --- a/rustbook-en/src/ch07-05-separating-modules-into-different-files.md +++ b/rustbook-en/src/ch07-05-separating-modules-into-different-files.md @@ -16,28 +16,26 @@ the `mod front_of_house;` declaration, so that *src/lib.rs* contains the code shown in Listing 7-21. Note that this won’t compile until we create the *src/front_of_house.rs* file in Listing 7-22. -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-21-and-22/src/lib.rs}} ``` -Listing 7-21: Declaring the `front_of_house` module whose -body will be in *src/front_of_house.rs* + Next, place the code that was in the curly brackets into a new file named *src/front_of_house.rs*, as shown in Listing 7-22. The compiler knows to look in this file because it came across the module declaration in the crate root with the name `front_of_house`. -Filename: src/front_of_house.rs + ```rust,ignore {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-21-and-22/src/front_of_house.rs}} ``` -Listing 7-22: Definitions inside the `front_of_house` -module in *src/front_of_house.rs* + Note that you only need to load a file using a `mod` declaration *once* in your module tree. Once the compiler knows the file is part of the project (and knows @@ -56,21 +54,25 @@ named for its ancestors in the module tree, in this case *src/front_of_house*. To start moving `hosting`, we change *src/front_of_house.rs* to contain only the declaration of the `hosting` module: -Filename: src/front_of_house.rs + ```rust,ignore {{#rustdoc_include ../listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/src/front_of_house.rs}} ``` + + Then we create a *src/front_of_house* directory and a *hosting.rs* file to contain the definitions made in the `hosting` module: -Filename: src/front_of_house/hosting.rs + ```rust,ignore {{#rustdoc_include ../listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/src/front_of_house/hosting.rs}} ``` + + If we instead put *hosting.rs* in the *src* directory, the compiler would expect the *hosting.rs* code to be in a `hosting` module declared in the crate root, and not declared as a child of the `front_of_house` module. The diff --git a/rustbook-en/src/ch08-01-vectors.md b/rustbook-en/src/ch08-01-vectors.md index 7138b35fd..c29728a7a 100644 --- a/rustbook-en/src/ch08-01-vectors.md +++ b/rustbook-en/src/ch08-01-vectors.md @@ -11,12 +11,13 @@ lines of text in a file or the prices of items in a shopping cart. To create a new empty vector, we call the `Vec::new` function, as shown in Listing 8-1. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-01/src/main.rs:here}} ``` -Listing 8-1: Creating a new, empty vector to hold values -of type `i32` + Note that we added a type annotation here. Because we aren’t inserting any values into this vector, Rust doesn’t know what kind of elements we intend to @@ -35,12 +36,13 @@ new vector that holds the values you give it. Listing 8-2 creates a new because that’s the default integer type, as we discussed in the [“Data Types”][data-types] section of Chapter 3. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-02/src/main.rs:here}} ``` -Listing 8-2: Creating a new vector containing -values + Because we’ve given initial `i32` values, Rust can infer that the type of `v` is `Vec`, and the type annotation isn’t necessary. Next, we’ll look at how @@ -51,12 +53,13 @@ to modify a vector. To create a vector and then add elements to it, we can use the `push` method, as shown in Listing 8-3. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-03/src/main.rs:here}} ``` -Listing 8-3: Using the `push` method to add values to a -vector + As with any variable, if we want to be able to change its value, we need to make it mutable using the `mut` keyword, as discussed in Chapter 3. The numbers @@ -72,12 +75,13 @@ the values that are returned from these functions for extra clarity. Listing 8-4 shows both methods of accessing a value in a vector, with indexing syntax and the `get` method. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-04/src/main.rs:here}} ``` -Listing 8-4: Using indexing syntax and using the `get` -method to access an item in a vector + Note a few details here. We use the index value of `2` to get the third element because vectors are indexed by number, starting at zero. Using `&` and `[]` @@ -91,12 +95,13 @@ existing elements. As an example, let’s see what happens when we have a vector of five elements and then we try to access an element at index 100 with each technique, as shown in Listing 8-5. ++ ```rust,should_panic,panics {{#rustdoc_include ../listings/ch08-common-collections/listing-08-05/src/main.rs:here}} ``` -Listing 8-5: Attempting to access the element at index -100 in a vector containing five elements + When we run this code, the first `[]` method will cause the program to panic because it references a nonexistent element. This method is best used when you @@ -123,12 +128,13 @@ to the first element in a vector and try to add an element to the end. This program won’t work if we also try to refer to that element later in the function. ++ ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch08-common-collections/listing-08-06/src/main.rs:here}} ``` -Listing 8-6: Attempting to add an element to a vector -while holding a reference to an item + Compiling this code will result in this error: @@ -156,23 +162,25 @@ elements rather than use indices to access one at a time. Listing 8-7 shows how to use a `for` loop to get immutable references to each element in a vector of `i32` values and print them. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-07/src/main.rs:here}} ``` -Listing 8-7: Printing each element in a vector by -iterating over the elements using a `for` loop + We can also iterate over mutable references to each element in a mutable vector in order to make changes to all the elements. The `for` loop in Listing 8-8 will add `50` to each element. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-08/src/main.rs:here}} ``` -Listing 8-8: Iterating over mutable references to -elements in a vector + To change the value that the mutable reference refers to, we have to use the `*` dereference operator to get to the value in `i` before we can use the `+=` @@ -202,12 +210,13 @@ value types, and all the enum variants will be considered the same type: that of the enum. Then we can create a vector to hold that enum and so, ultimately, hold different types. We’ve demonstrated this in Listing 8-9. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-09/src/main.rs:here}} ``` -Listing 8-9: Defining an `enum` to store values of -different types in one vector + Rust needs to know what types will be in the vector at compile time so it knows exactly how much memory on the heap will be needed to store each element. We @@ -231,12 +240,13 @@ addition to `push`, a `pop` method removes and returns the last element. Like any other `struct`, a vector is freed when it goes out of scope, as annotated in Listing 8-10. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-10/src/main.rs:here}} ``` -Listing 8-10: Showing where the vector and its elements -are dropped + When the vector gets dropped, all of its contents are also dropped, meaning the integers it holds will be cleaned up. The borrow checker ensures that any diff --git a/rustbook-en/src/ch08-02-strings.md b/rustbook-en/src/ch08-02-strings.md index be0c87474..9494fd94c 100644 --- a/rustbook-en/src/ch08-02-strings.md +++ b/rustbook-en/src/ch08-02-strings.md @@ -41,11 +41,13 @@ of bytes with some extra guarantees, restrictions, and capabilities. An example of a function that works the same way with `Vec` and `String` is the `new` function to create an instance, shown in Listing 8-11. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-11/src/main.rs:here}} ``` -Listing 8-11: Creating a new, empty `String` + This line creates a new, empty string called `s`, into which we can then load data. Often, we’ll have some initial data with which we want to start the @@ -53,12 +55,13 @@ string. For that, we use the `to_string` method, which is available on any type that implements the `Display` trait, as string literals do. Listing 8-12 shows two examples. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-12/src/main.rs:here}} ``` -Listing 8-12: Using the `to_string` method to create a -`String` from a string literal + This code creates a string containing `initial contents`. @@ -66,12 +69,13 @@ We can also use the function `String::from` to create a `String` from a string literal. The code in Listing 8-13 is equivalent to the code in Listing 8-12 that uses `to_string`. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-13/src/main.rs:here}} ``` -Listing 8-13: Using the `String::from` function to create -a `String` from a string literal + Because strings are used for so many things, we can use many different generic APIs for strings, providing us with a lot of options. Some of them can seem @@ -82,12 +86,13 @@ readability. Remember that strings are UTF-8 encoded, so we can include any properly encoded data in them, as shown in Listing 8-14. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-14/src/main.rs:here}} ``` -Listing 8-14: Storing greetings in different languages in -strings + All of these are valid `String` values. @@ -102,24 +107,26 @@ use the `+` operator or the `format!` macro to concatenate `String` values. We can grow a `String` by using the `push_str` method to append a string slice, as shown in Listing 8-15. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-15/src/main.rs:here}} ``` -Listing 8-15: Appending a string slice to a `String` -using the `push_str` method + After these two lines, `s` will contain `foobar`. The `push_str` method takes a string slice because we don’t necessarily want to take ownership of the parameter. For example, in the code in Listing 8-16, we want to be able to use `s2` after appending its contents to `s1`. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-16/src/main.rs:here}} ``` -Listing 8-16: Using a string slice after appending its -contents to a `String` + If the `push_str` method took ownership of `s2`, we wouldn’t be able to print its value on the last line. However, this code works as we’d expect! @@ -128,12 +135,13 @@ The `push` method takes a single character as a parameter and adds it to the `String`. Listing 8-17 adds the letter *l* to a `String` using the `push` method. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-17/src/main.rs:here}} ``` -Listing 8-17: Adding one character to a `String` value -using `push` + As a result, `s` will contain `lol`. @@ -142,12 +150,13 @@ As a result, `s` will contain `lol`. Often, you’ll want to combine two existing strings. One way to do so is to use the `+` operator, as shown in Listing 8-18. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-18/src/main.rs:here}} ``` -Listing 8-18: Using the `+` operator to combine two -`String` values into a new `String` value + The string `s3` will contain `Hello, world!`. The reason `s1` is no longer valid after the addition, and the reason we used a reference to `s2`, has to do @@ -215,12 +224,13 @@ string by referencing them by index is a valid and common operation. However, if you try to access parts of a `String` using indexing syntax in Rust, you’ll get an error. Consider the invalid code in Listing 8-19. ++ ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch08-common-collections/listing-08-19/src/main.rs:here}} ``` -Listing 8-19: Attempting to use indexing syntax with a -String + This code will result in the following error: diff --git a/rustbook-en/src/ch08-03-hash-maps.md b/rustbook-en/src/ch08-03-hash-maps.md index 72331e5b9..057501415 100644 --- a/rustbook-en/src/ch08-03-hash-maps.md +++ b/rustbook-en/src/ch08-03-hash-maps.md @@ -24,12 +24,13 @@ One way to create an empty hash map is to use `new` and to add elements with names are *Blue* and *Yellow*. The Blue team starts with 10 points, and the Yellow team starts with 50. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-20/src/main.rs:here}} ``` -Listing 8-20: Creating a new hash map and inserting some -keys and values + Note that we need to first `use` the `HashMap` from the collections portion of the standard library. Of our three common collections, this one is the least @@ -47,12 +48,13 @@ must have the same type. We can get a value out of the hash map by providing its key to the `get` method, as shown in Listing 8-21. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-21/src/main.rs:here}} ``` -Listing 8-21: Accessing the score for the Blue team -stored in the hash map + Here, `score` will have the value that’s associated with the Blue team, and the result will be `10`. The `get` method returns an `Option<&V>`; if there’s no @@ -81,12 +83,13 @@ For types that implement the `Copy` trait, like `i32`, the values are copied into the hash map. For owned values like `String`, the values will be moved and the hash map will be the owner of those values, as demonstrated in Listing 8-22. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-22/src/main.rs:here}} ``` -Listing 8-22: Showing that keys and values are owned by -the hash map once they’re inserted + We aren’t able to use the variables `field_name` and `field_value` after they’ve been moved into the hash map with the call to `insert`. @@ -120,12 +123,13 @@ Even though the code in Listing 8-23 calls `insert` twice, the hash map will only contain one key–value pair because we’re inserting the value for the Blue team’s key both times. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-23/src/main.rs:here}} ``` -Listing 8-23: Replacing a value stored with a particular -key + This code will print `{"Blue": 25}`. The original value of `10` has been overwritten. @@ -147,12 +151,13 @@ we want to check whether the key for the Yellow team has a value associated with it. If it doesn’t, we want to insert the value `50`, and the same for the Blue team. Using the `entry` API, the code looks like Listing 8-24. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-24/src/main.rs:here}} ``` -Listing 8-24: Using the `entry` method to only insert if -the key does not already have a value + The `or_insert` method on `Entry` is defined to return a mutable reference to the value for the corresponding `Entry` key if that key exists, and if not, it @@ -175,12 +180,13 @@ the words as keys and increment the value to keep track of how many times we’v seen that word. If it’s the first time we’ve seen a word, we’ll first insert the value `0`. ++ ```rust {{#rustdoc_include ../listings/ch08-common-collections/listing-08-25/src/main.rs:here}} ``` -Listing 8-25: Counting occurrences of words using a hash -map that stores words and counts + This code will print `{"world": 2, "hello": 1, "wonderful": 1}`. You might see the same key–value pairs printed in a different order: recall from the diff --git a/rustbook-en/src/ch09-01-unrecoverable-errors-with-panic.md b/rustbook-en/src/ch09-01-unrecoverable-errors-with-panic.md index 5c27c8f07..2fc98835c 100644 --- a/rustbook-en/src/ch09-01-unrecoverable-errors-with-panic.md +++ b/rustbook-en/src/ch09-01-unrecoverable-errors-with-panic.md @@ -31,12 +31,14 @@ panic occurs to make it easier to track down the source of the panic. Let’s try calling `panic!` in a simple program: -Filename: src/main.rs + ```rust,should_panic,panics {{#rustdoc_include ../listings/ch09-error-handling/no-listing-01-panic/src/main.rs}} ``` + + When you run the program, you’ll see something like this: ```console @@ -64,14 +66,13 @@ a `panic!` call comes from a library because of a bug in our code instead of from our code calling the macro directly. Listing 9-1 has some code that attempts to access an index in a vector beyond the range of valid indexes. -Filename: src/main.rs + ```rust,should_panic,panics {{#rustdoc_include ../listings/ch09-error-handling/listing-09-01/src/main.rs}} ``` -Listing 9-1: Attempting to access an element beyond the -end of a vector, which will cause a call to `panic!` + Here, we’re attempting to access the 100th element of our vector (which is at index 99 because indexing starts at zero), but the vector has only three @@ -117,6 +118,8 @@ copy the backtrace output below check the backtrace number mentioned in the text below the listing --> ++ ```console $ RUST_BACKTRACE=1 cargo run thread 'main' panicked at src/main.rs:4:6: @@ -141,8 +144,7 @@ stack backtrace: note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. ``` -Listing 9-2: The backtrace generated by a call to -`panic!` displayed when the environment variable `RUST_BACKTRACE` is set + That’s a lot of output! The exact output you see might be different depending on your operating system and Rust version. In order to get backtraces with this diff --git a/rustbook-en/src/ch09-02-recoverable-errors-with-result.md b/rustbook-en/src/ch09-02-recoverable-errors-with-result.md index 41031c127..81f628192 100644 --- a/rustbook-en/src/ch09-02-recoverable-errors-with-result.md +++ b/rustbook-en/src/ch09-02-recoverable-errors-with-result.md @@ -29,13 +29,13 @@ return may differ. Let’s call a function that returns a `Result` value because the function could fail. In Listing 9-3 we try to open a file. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch09-error-handling/listing-09-03/src/main.rs}} ``` -Listing 9-3: Opening a file + The return type of `File::open` is a `Result`. The generic parameter `T` has been filled in by the implementation of `File::open` with the type of the @@ -59,14 +59,13 @@ on the value `File::open` returns. Listing 9-4 shows one way to handle the `Result` using a basic tool, the `match` expression that we discussed in Chapter 6. -Filename: src/main.rs + ```rust,should_panic {{#rustdoc_include ../listings/ch09-error-handling/listing-09-04/src/main.rs}} ``` -Listing 9-4: Using a `match` expression to handle the -`Result` variants that might be returned + Note that, like the `Option` enum, the `Result` enum and its variants have been brought into scope by the prelude, so we don’t need to specify `Result::` @@ -98,7 +97,7 @@ reason—for example, because we didn’t have permission to open the file—we want the code to `panic!` in the same way it did in Listing 9-4. For this, we add an inner `match` expression, shown in Listing 9-5. -Filename: src/main.rs + @@ -107,8 +106,7 @@ tests to fail lol --> {{#rustdoc_include ../listings/ch09-error-handling/listing-09-05/src/main.rs}} ``` -Listing 9-5: Handling different kinds of errors in -different ways + The type of the value that `File::open` returns inside the `Err` variant is `io::Error`, which is a struct provided by the standard library. This struct @@ -172,12 +170,14 @@ Listing 9-4. If the `Result` value is the `Ok` variant, `unwrap` will return the value inside the `Ok`. If the `Result` is the `Err` variant, `unwrap` will call the `panic!` macro for us. Here is an example of `unwrap` in action: -Filename: src/main.rs + ```rust,should_panic {{#rustdoc_include ../listings/ch09-error-handling/no-listing-04-unwrap/src/main.rs}} ``` + + If we run this code without a *hello.txt* file, we’ll see an error message from the `panic!` call that the `unwrap` method makes: @@ -197,12 +197,14 @@ Using `expect` instead of `unwrap` and providing good error messages can convey your intent and make tracking down the source of a panic easier. The syntax of `expect` looks like this: -Filename: src/main.rs + ```rust,should_panic {{#rustdoc_include ../listings/ch09-error-handling/no-listing-05-expect/src/main.rs}} ``` + + We use `expect` in the same way as `unwrap`: to return the file handle or call the `panic!` macro. The error message used by `expect` in its call to `panic!` will be the parameter that we pass to `expect`, rather than the default @@ -237,7 +239,7 @@ For example, Listing 9-6 shows a function that reads a username from a file. If the file doesn’t exist or can’t be read, this function will return those errors to the code that called the function. -Filename: src/main.rs + {{#include ../listings/ch09-error-handling/listing-09-06/src/main.rs:here}} ``` -Listing 9-6: A function that returns errors to the -calling code using `match` + This function can be written in a much shorter way, but we’re going to start by doing a lot of it manually in order to explore error handling; at the end, @@ -307,7 +308,7 @@ Listing 9-7 shows an implementation of `read_username_from_file` that has the same functionality as in Listing 9-6, but this implementation uses the `?` operator. -Filename: src/main.rs + {{#include ../listings/ch09-error-handling/listing-09-07/src/main.rs:here}} ``` -Listing 9-7: A function that returns errors to the -calling code using the `?` operator + The `?` placed after a `Result` value is defined to work in almost the same way as the `match` expressions we defined to handle the `Result` values in Listing @@ -355,7 +355,7 @@ The `?` operator eliminates a lot of boilerplate and makes this function’s implementation simpler. We could even shorten this code further by chaining method calls immediately after the `?`, as shown in Listing 9-8. -Filename: src/main.rs + {{#include ../listings/ch09-error-handling/listing-09-08/src/main.rs:here}} ``` -Listing 9-8: Chaining method calls after the `?` -operator + We’ve moved the creation of the new `String` in `username` to the beginning of the function; that part hasn’t changed. Instead of creating a variable @@ -379,7 +378,7 @@ this is just a different, more ergonomic way to write it. Listing 9-9 shows a way to make this even shorter using `fs::read_to_string`. -Filename: src/main.rs + {{#include ../listings/ch09-error-handling/listing-09-09/src/main.rs:here}} ``` -Listing 9-9: Using `fs::read_to_string` instead of -opening and then reading the file + Reading a file into a string is a fairly common operation, so the standard library provides the convenient `fs::read_to_string` function that opens the @@ -413,14 +411,13 @@ In Listing 9-10, let’s look at the error we’ll get if we use the `?` operato in a `main` function with a return type that is incompatible with the type of the value we use `?` on. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch09-error-handling/listing-09-10/src/main.rs}} ``` -Listing 9-10: Attempting to use the `?` in the `main` -function that returns `()` won’t compile. + This code opens a file, which might fail. The `?` operator follows the `Result` value returned by `File::open`, but this `main` function has the return type of @@ -451,12 +448,13 @@ resultant value of the expression, and the function continues. Listing 9-11 has an example of a function that finds the last character of the first line in the given text. ++ ```rust {{#rustdoc_include ../listings/ch09-error-handling/listing-09-11/src/main.rs:here}} ``` -Listing 9-11: Using the `?` operator on an `Option` -value + This function returns `Option` because it’s possible that there is a character there, but it’s also possible that there isn’t. This code takes the @@ -496,14 +494,13 @@ from Listing 9-10, but we’ve changed the return type of `main` to be `Result<(), Box>` and added a return value `Ok(())` to the end. This code will now compile. -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch09-error-handling/listing-09-12/src/main.rs}} ``` -Listing 9-12: Changing `main` to return `Result<(), E>` -allows the use of the `?` operator on `Result` values. + The `Box` type is a *trait object*, which we’ll talk about in the [“Using Trait Objects that Allow for Values of Different diff --git a/rustbook-en/src/ch09-03-to-panic-or-not-to-panic.md b/rustbook-en/src/ch09-03-to-panic-or-not-to-panic.md index 88e30fd5e..9b7850ca9 100644 --- a/rustbook-en/src/ch09-03-to-panic-or-not-to-panic.md +++ b/rustbook-en/src/ch09-03-to-panic-or-not-to-panic.md @@ -140,12 +140,14 @@ One way to do this would be to parse the guess as an `i32` instead of only a `u32` to allow potentially negative numbers, and then add a check for the number being in range, like so: -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch09-error-handling/no-listing-09-guess-out-of-range/src/main.rs:here}} ``` + + The `if` expression checks whether our value is out of range, tells the user about the problem, and calls `continue` to start the next iteration of the loop and ask for another guess. After the `if` expression, we can proceed with the @@ -164,14 +166,13 @@ confidently use the values they receive. Listing 9-13 shows one way to define a `Guess` type that will only create an instance of `Guess` if the `new` function receives a value between 1 and 100. -Filename: src/lib.rs + ```rust {{#rustdoc_include ../listings/ch09-error-handling/listing-09-13/src/lib.rs}} ``` -Listing 9-13: A `Guess` type that will only continue with -values between 1 and 100 + First we define a struct named `Guess` that has a field named `value` that holds an `i32`. This is where the number will be stored. diff --git a/rustbook-en/src/ch10-00-generics.md b/rustbook-en/src/ch10-00-generics.md index 56ceee20d..2e68384e1 100644 --- a/rustbook-en/src/ch10-00-generics.md +++ b/rustbook-en/src/ch10-00-generics.md @@ -42,14 +42,13 @@ duplicated code that can use generics. We’ll begin with the short program in Listing 10-1 that finds the largest number in a list. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-01/src/main.rs:here}} ``` -Listing 10-1: Finding the largest number in a list of -numbers + We store a list of integers in the variable `number_list` and place a reference to the first number in the list in a variable named `largest`. We then iterate @@ -64,14 +63,13 @@ We’ve now been tasked with finding the largest number in two different lists o numbers. To do so, we can choose to duplicate the code in Listing 10-1 and use the same logic at two different places in the program, as shown in Listing 10-2. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-02/src/main.rs}} ``` -Listing 10-2: Code to find the largest number in *two* -lists of numbers + Although this code works, duplicating code is tedious and error prone. We also have to remember to update the code in multiple places when we want to change @@ -87,14 +85,13 @@ function named `largest`. Then we call the function to find the largest number in the two lists from Listing 10-2. We could also use the function on any other list of `i32` values we might have in the future. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-03/src/main.rs:here}} ``` -Listing 10-3: Abstracted code to find the largest number -in two lists + The `largest` function has a parameter called `list`, which represents any concrete slice of `i32` values we might pass into the function. As a result, diff --git a/rustbook-en/src/ch10-01-syntax.md b/rustbook-en/src/ch10-01-syntax.md index 0b71c04c5..2a22baf58 100644 --- a/rustbook-en/src/ch10-01-syntax.md +++ b/rustbook-en/src/ch10-01-syntax.md @@ -16,14 +16,13 @@ Continuing with our `largest` function, Listing 10-4 shows two functions that both find the largest value in a slice. We’ll then combine these into a single function that uses generics. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-04/src/main.rs:here}} ``` -Listing 10-4: Two functions that differ only in their -names and in the types in their signatures + The `largest_i32` function is the one we extracted in Listing 10-3 that finds the largest `i32` in a slice. The `largest_char` function finds the largest @@ -58,14 +57,13 @@ data type in its signature. The listing also shows how we can call the function with either a slice of `i32` values or `char` values. Note that this code won’t compile yet, but we’ll fix it later in this chapter. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs}} ``` -Listing 10-5: The `largest` function using generic type -parameters; this doesn’t compile yet + If we compile this code right now, we’ll get this error: @@ -90,14 +88,13 @@ We can also define structs to use a generic type parameter in one or more fields using the `<>` syntax. Listing 10-6 defines a `Point` struct to hold `x` and `y` coordinate values of any type. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-06/src/main.rs}} ``` -Listing 10-6: A `Point` struct that holds `x` and `y` -values of type `T` + The syntax for using generics in struct definitions is similar to that used in function definitions. First we declare the name of the type parameter inside @@ -111,14 +108,13 @@ the fields `x` and `y` are *both* that same type, whatever that type may be. If we create an instance of a `Point` that has values of different types, as in Listing 10-7, our code won’t compile. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-07/src/main.rs}} ``` -Listing 10-7: The fields `x` and `y` must be the same -type because both have the same generic data type `T`. + In this example, when we assign the integer value `5` to `x`, we let the compiler know that the generic type `T` will be an integer for this instance of @@ -134,14 +130,13 @@ different types, we can use multiple generic type parameters. For example, in Listing 10-8, we change the definition of `Point` to be generic over types `T` and `U` where `x` is of type `T` and `y` is of type `U`. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-08/src/main.rs}} ``` -Listing 10-8: A `Point` generic over two types so -that `x` and `y` can be values of different types + Now all the instances of `Point` shown are allowed! You can use as many generic type parameters in a definition as you want, but using more than a few makes @@ -198,15 +193,13 @@ We can implement methods on structs and enums (as we did in Chapter 5) and use generic types in their definitions too. Listing 10-9 shows the `Point` struct we defined in Listing 10-6 with a method named `x` implemented on it. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-09/src/main.rs}} ``` -Listing 10-9: Implementing a method named `x` on the -`Point` struct that will return a reference to the `x` field of type -`T` + Here, we’ve defined a method named `x` on `Point` that returns a reference to the data in the field `x`. @@ -226,14 +219,13 @@ type. We could, for example, implement methods only on `Point` instances rather than on `Point` instances with any generic type. In Listing 10-10 we use the concrete type `f32`, meaning we don’t declare any types after `impl`. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-10/src/main.rs:here}} ``` -Listing 10-10: An `impl` block that only applies to a -struct with a particular concrete type for the generic type parameter `T` + This code means the type `Point` will have a `distance_from_origin` method; other instances of `Point` where `T` is not of type `f32` will not @@ -248,14 +240,13 @@ signature to make the example clearer. The method creates a new `Point` instance with the `x` value from the `self` `Point` (of type `X1`) and the `y` value from the passed-in `Point` (of type `Y2`). -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-11/src/main.rs}} ``` -Listing 10-11: A method that uses generic types different -from its struct’s definition + In `main`, we’ve defined a `Point` that has an `i32` for `x` (with value `5`) and an `f64` for `y` (with value `10.4`). The `p2` variable is a `Point` struct @@ -304,7 +295,7 @@ definition with the specific ones. The monomorphized version of the code looks similar to the following (the compiler uses different names than what we’re using here for illustration): -Filename: src/main.rs + ```rust enum Option_i32 { @@ -323,6 +314,8 @@ fn main() { } ``` + + The generic `Option` is replaced with the specific definitions created by the compiler. Because Rust compiles generic code into code that specifies the type in each instance, we pay no runtime cost for using generics. When the code diff --git a/rustbook-en/src/ch10-02-traits.md b/rustbook-en/src/ch10-02-traits.md index 25eaaa3cc..d9c40518e 100644 --- a/rustbook-en/src/ch10-02-traits.md +++ b/rustbook-en/src/ch10-02-traits.md @@ -27,14 +27,13 @@ instance. To do this, we need a summary from each type, and we’ll request that summary by calling a `summarize` method on an instance. Listing 10-12 shows the definition of a public `Summary` trait that expresses this behavior. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-12/src/lib.rs}} ``` -Listing 10-12: A `Summary` trait that consists of the -behavior provided by a `summarize` method + Here, we declare a trait using the `trait` keyword and then the trait’s name, which is `Summary` in this case. We also declare the trait as `pub` so that @@ -62,14 +61,13 @@ the headline, the author, and the location to create the return value of followed by the entire text of the tweet, assuming that the tweet content is already limited to 280 characters. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/src/lib.rs:here}} ``` -Listing 10-13: Implementing the `Summary` trait on the -`NewsArticle` and `Tweet` types + Implementing a trait on a type is similar to implementing regular methods. The difference is that after `impl`, we put the trait name we want to implement, @@ -124,14 +122,13 @@ In Listing 10-14, we specify a default string for the `summarize` method of the `Summary` trait instead of only defining the method signature, as we did in Listing 10-12. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-14/src/lib.rs:here}} ``` -Listing 10-14: Defining a `Summary` trait with a default -implementation of the `summarize` method + To use a default implementation to summarize instances of `NewsArticle`, we specify an empty `impl` block with `impl Summary for NewsArticle {}`. @@ -339,14 +336,13 @@ is a type alias for the type of the `impl` block, which in this case is `cmp_display` method if its inner type `T` implements the `PartialOrd` trait that enables comparison *and* the `Display` trait that enables printing. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/src/lib.rs}} ``` -Listing 10-15: Conditionally implementing methods on a -generic type depending on trait bounds + We can also conditionally implement a trait for any type that implements another trait. Implementations of a trait on any type that satisfies the trait diff --git a/rustbook-en/src/ch10-03-lifetime-syntax.md b/rustbook-en/src/ch10-03-lifetime-syntax.md index c87f38c4c..d9922d38a 100644 --- a/rustbook-en/src/ch10-03-lifetime-syntax.md +++ b/rustbook-en/src/ch10-03-lifetime-syntax.md @@ -26,12 +26,13 @@ program to reference data other than the data it’s intended to reference. Consider the program in Listing 10-16, which has an outer scope and an inner scope. ++ ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-16/src/main.rs}} ``` -Listing 10-16: An attempt to use a reference whose value -has gone out of scope + > Note: The examples in Listing 10-16, 10-17, and 10-23 declare variables > without giving them an initial value, so the variable name exists in the outer @@ -65,12 +66,13 @@ The Rust compiler has a *borrow checker* that compares scopes to determine whether all borrows are valid. Listing 10-17 shows the same code as Listing 10-16 but with annotations showing the lifetimes of the variables. ++ ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-17/src/main.rs}} ``` -Listing 10-17: Annotations of the lifetimes of `r` and -`x`, named `'a` and `'b`, respectively + Here, we’ve annotated the lifetime of `r` with `'a` and the lifetime of `x` with `'b`. As you can see, the inner `'b` block is much smaller than the outer @@ -82,12 +84,13 @@ with a lifetime of `'b`. The program is rejected because `'b` is shorter than Listing 10-18 fixes the code so it doesn’t have a dangling reference and it compiles without any errors. ++ ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-18/src/main.rs}} ``` -Listing 10-18: A valid reference because the data has a -longer lifetime than the reference + Here, `x` has the lifetime `'b`, which in this case is larger than `'a`. This means `r` can reference `x` because Rust knows that the reference in `r` will @@ -104,14 +107,13 @@ function will take two string slices and return a single string slice. After we’ve implemented the `longest` function, the code in Listing 10-19 should print `The longest string is abcd`. -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-19/src/main.rs}} ``` -Listing 10-19: A `main` function that calls the `longest` -function to find the longer of two string slices + Note that we want the function to take string slices, which are references, rather than strings, because we don’t want the `longest` function to take @@ -123,15 +125,13 @@ ones we want. If we try to implement the `longest` function as shown in Listing 10-20, it won’t compile. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/src/main.rs:here}} ``` -Listing 10-20: An implementation of the `longest` -function that returns the longer of two string slices but does not yet -compile + Instead, we get the following error that talks about lifetimes: @@ -197,15 +197,13 @@ relationship between lifetimes of the parameters and the return value. We’ll name the lifetime `'a` and then add it to each reference, as shown in Listing 10-21. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-21/src/main.rs:here}} ``` -Listing 10-21: The `longest` function definition -specifying that all the references in the signature must have the same lifetime -`'a` + This code should compile and produce the result we want when we use it with the `main` function in Listing 10-19. @@ -249,14 +247,13 @@ Let’s look at how the lifetime annotations restrict the `longest` function by passing in references that have different concrete lifetimes. Listing 10-22 is a straightforward example. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-22/src/main.rs:here}} ``` -Listing 10-22: Using the `longest` function with -references to `String` values that have different concrete lifetimes + In this example, `string1` is valid until the end of the outer scope, `string2` is valid until the end of the inner scope, and `result` references something @@ -272,14 +269,13 @@ assignment of the value to the `result` variable inside the scope with inner scope, after the inner scope has ended. The code in Listing 10-23 will not compile. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-23/src/main.rs:here}} ``` -Listing 10-23: Attempting to use `result` after `string2` -has gone out of scope + When we try to compile this code, we get this error: @@ -314,12 +310,14 @@ function is doing. For example, if we changed the implementation of the string slice, we wouldn’t need to specify a lifetime on the `y` parameter. The following code will compile: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-08-only-one-reference-with-lifetime/src/main.rs:here}} ``` + + We’ve specified a lifetime parameter `'a` for the parameter `x` and the return type, but not for the parameter `y`, because the lifetime of `y` does not have any relationship with the lifetime of `x` or the return value. @@ -332,12 +330,14 @@ reference because the value will go out of scope at the end of the function. Consider this attempted implementation of the `longest` function that won’t compile: -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-09-unrelated-lifetime/src/main.rs:here}} ``` + + Here, even though we’ve specified a lifetime parameter `'a` for the return type, this implementation will fail to compile because the return value lifetime is not related to the lifetime of the parameters at all. Here is the @@ -367,14 +367,13 @@ to hold references, but in that case we would need to add a lifetime annotation on every reference in the struct’s definition. Listing 10-24 has a struct named `ImportantExcerpt` that holds a string slice. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-24/src/main.rs}} ``` -Listing 10-24: A struct that holds a reference, requiring -a lifetime annotation + This struct has the single field `part` that holds a string slice, which is a reference. As with generic data types, we declare the name of the generic @@ -397,15 +396,13 @@ lifetime parameters for functions or structs that use references. However, we had a function in Listing 4-9, shown again in Listing 10-25, that compiled without lifetime annotations. -Filename: src/lib.rs + ```rust {{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-25/src/main.rs:here}} ``` -Listing 10-25: A function we defined in Listing 4-9 that -compiled without lifetime annotations, even though the parameter and return -type are references + The reason this function compiles without lifetime annotations is historical: in early versions (pre-1.0) of Rust, this code wouldn’t have compiled because diff --git a/rustbook-en/src/ch15-01-box.md b/rustbook-en/src/ch15-01-box.md index bc16c2504..548152b5c 100644 --- a/rustbook-en/src/ch15-01-box.md +++ b/rustbook-en/src/ch15-01-box.md @@ -35,14 +35,13 @@ syntax and how to interact with values stored within a `Box`. Listing 15-1 shows how to use a box to store an `i32` value on the heap: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-01/src/main.rs}} ``` -Listing 15-1: Storing an `i32` value on the heap using a -box + We define the variable `b` to have the value of a `Box` that points to the value `5`, which is allocated on the heap. This program will print `b = 5`; in @@ -106,14 +105,13 @@ Listing 15-2 contains an enum definition for a cons list. Note that this code won’t compile yet because the `List` type doesn’t have a known size, which we’ll demonstrate. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-02/src/main.rs:here}} ``` -Listing 15-2: The first attempt at defining an enum to -represent a cons list data structure of `i32` values + > Note: We’re implementing a cons list that holds only `i32` values for the > purposes of this example. We could have implemented it using generics, as we @@ -123,14 +121,13 @@ represent a cons list data structure of `i32` values Using the `List` type to store the list `1, 2, 3` would look like the code in Listing 15-3: -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-03/src/main.rs:here}} ``` -Listing 15-3: Using the `List` enum to store the list `1, -2, 3` + The first `Cons` value holds `1` and another `List` value. This `List` value is another `Cons` value that holds `2` and another `List` value. This `List` value @@ -140,12 +137,13 @@ is one more `Cons` value that holds `3` and a `List` value, which is finally If we try to compile the code in Listing 15-3, we get the error shown in Listing 15-4: ++ ```console {{#include ../listings/ch15-smart-pointers/listing-15-03/output.txt}} ``` -Listing 15-4: The error we get when attempting to define -a recursive enum + The error shows this type “has infinite size.” The reason is that we’ve defined `List` with a variant that is recursive: it holds another value of itself @@ -215,14 +213,13 @@ rather than inside one another. We can change the definition of the `List` enum in Listing 15-2 and the usage of the `List` in Listing 15-3 to the code in Listing 15-5, which will compile: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-05/src/main.rs}} ``` -Listing 15-5: Definition of `List` that uses `Box` in -order to have a known size + The `Cons` variant needs the size of an `i32` plus the space to store the box’s pointer data. The `Nil` variant stores no values, so it needs less space diff --git a/rustbook-en/src/ch15-02-deref.md b/rustbook-en/src/ch15-02-deref.md index 5017fca43..449e472dc 100644 --- a/rustbook-en/src/ch15-02-deref.md +++ b/rustbook-en/src/ch15-02-deref.md @@ -29,14 +29,13 @@ as an arrow to a value stored somewhere else. In Listing 15-6, we create a reference to an `i32` value and then use the dereference operator to follow the reference to the value: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-06/src/main.rs}} ``` -Listing 15-6: Using the dereference operator to follow a -reference to an `i32` value + The variable `x` holds an `i32` value `5`. We set `y` equal to a reference to `x`. We can assert that `x` is equal to `5`. However, if we want to make an @@ -63,14 +62,13 @@ reference; the dereference operator used on the `Box` in Listing 15-7 functions in the same way as the dereference operator used on the reference in Listing 15-6: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-07/src/main.rs}} ``` -Listing 15-7: Using the dereference operator on a -`Box` + The main difference between Listing 15-7 and Listing 15-6 is that here we set `y` to be an instance of a `Box` pointing to a copied value of `x` rather @@ -91,13 +89,13 @@ The `Box` type is ultimately defined as a tuple struct with one element, so Listing 15-8 defines a `MyBox` type in the same way. We’ll also define a `new` function to match the `new` function defined on `Box`. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-08/src/main.rs:here}} ``` -Listing 15-8: Defining a `MyBox` type + We define a struct named `MyBox` and declare a generic parameter `T`, because we want our type to hold values of any type. The `MyBox` type is a tuple struct @@ -109,14 +107,13 @@ changing it to use the `MyBox` type we’ve defined instead of `Box`. The code in Listing 15-9 won’t compile because Rust doesn’t know how to dereference `MyBox`. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-09/src/main.rs:here}} ``` -Listing 15-9: Attempting to use `MyBox` in the same -way we used references and `Box` + Here’s the resulting compilation error: @@ -137,13 +134,13 @@ by the standard library, requires us to implement one method named `deref` that borrows `self` and returns a reference to the inner data. Listing 15-10 contains an implementation of `Deref` to add to the definition of `MyBox`: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-10/src/main.rs:here}} ``` -Listing 15-10: Implementing `Deref` on `MyBox` + The `type Target = T;` syntax defines an associated type for the `Deref` trait to use. Associated types are a slightly different way of declaring a @@ -210,27 +207,25 @@ Listing 15-8 as well as the implementation of `Deref` that we added in Listing 15-10. Listing 15-11 shows the definition of a function that has a string slice parameter: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-11/src/main.rs:here}} ``` -Listing 15-11: A `hello` function that has the parameter -`name` of type `&str` + We can call the `hello` function with a string slice as an argument, such as `hello("Rust");` for example. Deref coercion makes it possible to call `hello` with a reference to a value of type `MyBox`, as shown in Listing 15-12: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-12/src/main.rs:here}} ``` -Listing 15-12: Calling `hello` with a reference to a -`MyBox` value, which works because of deref coercion + Here we’re calling the `hello` function with the argument `&m`, which is a reference to a `MyBox` value. Because we implemented the `Deref` trait @@ -244,14 +239,13 @@ If Rust didn’t implement deref coercion, we would have to write the code in Listing 15-13 instead of the code in Listing 15-12 to call `hello` with a value of type `&MyBox`. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-13/src/main.rs:here}} ``` -Listing 15-13: The code we would have to write if Rust -didn’t have deref coercion + The `(*m)` dereferences the `MyBox` into a `String`. Then the `&` and `[..]` take a string slice of the `String` that is equal to the whole string to diff --git a/rustbook-en/src/ch15-03-drop.md b/rustbook-en/src/ch15-03-drop.md index 05ab86873..8c402f408 100644 --- a/rustbook-en/src/ch15-03-drop.md +++ b/rustbook-en/src/ch15-03-drop.md @@ -28,14 +28,13 @@ Listing 15-14 shows a `CustomSmartPointer` struct whose only custom functionality is that it will print `Dropping CustomSmartPointer!` when the instance goes out of scope, to show when Rust runs the `drop` function. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-14/src/main.rs}} ``` -Listing 15-14: A `CustomSmartPointer` struct that -implements the `Drop` trait where we would put our cleanup code + The `Drop` trait is included in the prelude, so we don’t need to bring it into scope. We implement the `Drop` trait on `CustomSmartPointer` and provide an @@ -79,14 +78,13 @@ If we try to call the `Drop` trait’s `drop` method manually by modifying the `main` function from Listing 15-14, as shown in Listing 15-15, we’ll get a compiler error: -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-15/src/main.rs:here}} ``` -Listing 15-15: Attempting to call the `drop` method from -the `Drop` trait manually to clean up early + When we try to compile this code, we’ll get this error: @@ -114,14 +112,13 @@ trait. We call it by passing as an argument the value we want to force drop. The function is in the prelude, so we can modify `main` in Listing 15-15 to call the `drop` function, as shown in Listing 15-16: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-16/src/main.rs:here}} ``` -Listing 15-16: Calling `std::mem::drop` to explicitly -drop a value before it goes out of scope + Running this code will print the following: diff --git a/rustbook-en/src/ch15-04-rc.md b/rustbook-en/src/ch15-04-rc.md index 87a42eb1a..c5bf9a489 100644 --- a/rustbook-en/src/ch15-04-rc.md +++ b/rustbook-en/src/ch15-04-rc.md @@ -48,14 +48,13 @@ words, both lists will share the first list containing 5 and 10. Trying to implement this scenario using our definition of `List` with `Box` won’t work, as shown in Listing 15-17: -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-17/src/main.rs}} ``` -Listing 15-17: Demonstrating we’re not allowed to have -two lists using `Box` that try to share ownership of a third list + When we compile this code, we get this error: @@ -84,14 +83,13 @@ we call `Rc::clone`, the reference count to the data within the `Rc` will increase, and the data won’t be cleaned up unless there are zero references to it. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-18/src/main.rs}} ``` -Listing 15-18: A definition of `List` that uses -`Rc` + We need to add a `use` statement to bring `Rc` into scope because it’s not in the prelude. In `main`, we create the list holding 5 and 10 and store it in @@ -118,13 +116,13 @@ counts changing as we create and drop references to the `Rc` in `a`. In Listing 15-19, we’ll change `main` so it has an inner scope around list `c`; then we can see how the reference count changes when `c` goes out of scope. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-19/src/main.rs:here}} ``` -Listing 15-19: Printing the reference count + At each point in the program where the reference count changes, we print the reference count, which we get by calling the `Rc::strong_count` function. This diff --git a/rustbook-en/src/ch15-05-interior-mutability.md b/rustbook-en/src/ch15-05-interior-mutability.md index 4c7d3c4f6..5b103dc0b 100644 --- a/rustbook-en/src/ch15-05-interior-mutability.md +++ b/rustbook-en/src/ch15-05-interior-mutability.md @@ -129,14 +129,13 @@ email, send a text message, or something else. The library doesn’t need to kno that detail. All it needs is something that implements a trait we’ll provide called `Messenger`. Listing 15-20 shows the library code: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-20/src/lib.rs}} ``` -Listing 15-20: A library to keep track of how close a -value is to a maximum value and warn when the value is at certain levels + One important part of this code is that the `Messenger` trait has one method called `send` that takes an immutable reference to `self` and the text of the @@ -156,14 +155,13 @@ mock object, call the `set_value` method on `LimitTracker`, and then check that the mock object has the messages we expect. Listing 15-21 shows an attempt to implement a mock object to do just that, but the borrow checker won’t allow it: -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-21/src/lib.rs:here}} ``` -Listing 15-21: An attempt to implement a `MockMessenger` -that isn’t allowed by the borrow checker + This test code defines a `MockMessenger` struct that has a `sent_messages` field with a `Vec` of `String` values to keep track of the messages it’s told @@ -200,14 +198,13 @@ This is a situation in which interior mutability can help! We’ll store the able to modify `sent_messages` to store the messages we’ve seen. Listing 15-22 shows what that looks like: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-22/src/lib.rs:here}} ``` -Listing 15-22: Using `RefCell` to mutate an inner -value while the outer value is considered immutable + The `sent_messages` field is now of type `RefCell>` instead of `Vec`. In the `new` function, we create a new `RefCell>` @@ -249,14 +246,13 @@ Listing 15-22. We’re deliberately trying to create two mutable borrows active for the same scope to illustrate that `RefCell` prevents us from doing this at runtime. -Filename: src/lib.rs + ```rust,ignore,panics {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-23/src/lib.rs:here}} ``` -Listing 15-23: Creating two mutable references in the -same scope to see that `RefCell` will panic + We create a variable `one_borrow` for the `RefMut` smart pointer returned from `borrow_mut`. Then we create another mutable borrow in the same way in the @@ -298,14 +294,13 @@ change the values in the lists. Listing 15-24 shows that by using a `RefCell` in the `Cons` definition, we can modify the value stored in all the lists: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-24/src/main.rs}} ``` -Listing 15-24: Using `Rc>` to create a -`List` that we can mutate + We create a value that is an instance of `Rc>` and store it in a variable named `value` so we can access it directly later. Then we create a diff --git a/rustbook-en/src/ch15-06-reference-cycles.md b/rustbook-en/src/ch15-06-reference-cycles.md index beb2bc216..2ea12edb6 100644 --- a/rustbook-en/src/ch15-06-reference-cycles.md +++ b/rustbook-en/src/ch15-06-reference-cycles.md @@ -15,14 +15,13 @@ Let’s look at how a reference cycle might happen and how to prevent it, starting with the definition of the `List` enum and a `tail` method in Listing 15-25: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-25/src/main.rs}} ``` -Listing 15-25: A cons list definition that holds a -`RefCell` so we can modify what a `Cons` variant is referring to + We’re using another variation of the `List` definition from Listing 15-5. The second element in the `Cons` variant is now `RefCell>`, meaning that @@ -37,14 +36,13 @@ the list in `a`. Then it modifies the list in `a` to point to `b`, creating a reference cycle. There are `println!` statements along the way to show what the reference counts are at various points in this process. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-26/src/main.rs:here}} ``` -Listing 15-26: Creating a reference cycle of two `List` -values pointing to each other + We create an `Rc` instance holding a `List` value in the variable `a` with an initial list of `5, Nil`. We then create an `Rc` instance holding @@ -163,14 +161,13 @@ Next, we’ll use our struct definition and create one `Node` instance named `leaf` with the value 3 and no children, and another instance named `branch` with the value 5 and `leaf` as one of its children, as shown in Listing 15-27: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-27/src/main.rs:there}} ``` -Listing 15-27: Creating a `leaf` node with no children -and a `branch` node with `leaf` as one of its children + We clone the `Rc` in `leaf` and store that in `branch`, meaning the `Node` in `leaf` now has two owners: `leaf` and `branch`. We can get from @@ -207,14 +204,13 @@ A node will be able to refer to its parent node but doesn’t own its parent. In Listing 15-28, we update `main` to use this new definition so the `leaf` node will have a way to refer to its parent, `branch`: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-28/src/main.rs:there}} ``` -Listing 15-28: A `leaf` node with a weak reference to its -parent node `branch` + Creating the `leaf` node looks similar to Listing 15-27 with the exception of the `parent` field: `leaf` starts out without a parent, so we create a new, @@ -260,14 +256,13 @@ instances change by creating a new inner scope and moving the creation of created and then dropped when it goes out of scope. The modifications are shown in Listing 15-29: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-29/src/main.rs:here}} ``` -Listing 15-29: Creating `branch` in an inner scope and -examining strong and weak reference counts + After `leaf` is created, its `Rc` has a strong count of 1 and a weak count of 0. In the inner scope, we create `branch` and associate it with diff --git a/rustbook-en/src/ch16-01-threads.md b/rustbook-en/src/ch16-01-threads.md index f3cdbff90..cc6466404 100644 --- a/rustbook-en/src/ch16-01-threads.md +++ b/rustbook-en/src/ch16-01-threads.md @@ -40,14 +40,13 @@ closure (we talked about closures in Chapter 13) containing the code we want to run in the new thread. The example in Listing 16-1 prints some text from a main thread and other text from a new thread: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-01/src/main.rs}} ``` -Listing 16-1: Creating a new thread to print one thing -while the main thread prints something else + Note that when the main thread of a Rust program completes, all spawned threads are shut down, whether or not they have finished running. The output from this @@ -96,14 +95,13 @@ call the `join` method on it, will wait for its thread to finish. Listing 16-2 shows how to use the `JoinHandle` of the thread we created in Listing 16-1 and call `join` to make sure the spawned thread finishes before `main` exits: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-02/src/main.rs}} ``` -Listing 16-2: Saving a `JoinHandle` from `thread::spawn` -to guarantee the thread is run to completion + Calling `join` on the handle blocks the thread currently running until the thread represented by the handle terminates. *Blocking* a thread means that @@ -137,12 +135,14 @@ call to `handle.join()` and does not end until the spawned thread is finished. But let’s see what happens when we instead move `handle.join()` before the `for` loop in `main`, like this: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/no-listing-01-join-too-early/src/main.rs}} ``` + + The main thread will wait for the spawned thread to finish and then run its `for` loop, so the output won’t be interleaved anymore, as shown here: @@ -185,14 +185,13 @@ spawned thread’s closure must capture the values it needs. Listing 16-3 shows an attempt to create a vector in the main thread and use it in the spawned thread. However, this won’t yet work, as you’ll see in a moment. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-03/src/main.rs}} ``` -Listing 16-3: Attempting to use a vector created by the -main thread in another thread + The closure uses `v`, so it will capture `v` and make it part of the closure’s environment. Because `thread::spawn` runs this closure in a new thread, we @@ -211,14 +210,13 @@ to `v` will always be valid. Listing 16-4 provides a scenario that’s more likely to have a reference to `v` that won’t be valid: -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-04/src/main.rs}} ``` -Listing 16-4: A thread with a closure that attempts to -capture a reference to `v` from a main thread that drops `v` + If Rust allowed us to run this code, there’s a possibility the spawned thread would be immediately put in the background without running at all. The spawned @@ -246,14 +244,14 @@ ownership of the values it’s using rather than allowing Rust to infer that it should borrow the values. The modification to Listing 16-3 shown in Listing 16-5 will compile and run as we intend: -Filename: src/main.rs ++ ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-05/src/main.rs}} ``` -Listing 16-5: Using the `move` keyword to force a closure -to take ownership of the values it uses + We might be tempted to try the same thing to fix the code in Listing 16-4 where the main thread called `drop` by using a `move` closure. However, this fix will diff --git a/rustbook-en/src/ch16-02-message-passing.md b/rustbook-en/src/ch16-02-message-passing.md index 3782fa5de..f2d396bfa 100644 --- a/rustbook-en/src/ch16-02-message-passing.md +++ b/rustbook-en/src/ch16-02-message-passing.md @@ -66,14 +66,13 @@ string so the spawned thread is communicating with the main thread, as shown in Listing 16-7. This is like putting a rubber duck in the river upstream or sending a chat message from one thread to another. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-07/src/main.rs}} ``` -Listing 16-7: Moving `tx` to a spawned thread and sending -“hi” + Again, we’re using `thread::spawn` to create a new thread and then using `move` to move `tx` into the closure so the spawned thread owns `tx`. The spawned @@ -89,14 +88,13 @@ In Listing 16-8, we’ll get the value from the receiver in the main thread. Thi is like retrieving the rubber duck from the water at the end of the river or receiving a chat message. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-08/src/main.rs}} ``` -Listing 16-8: Receiving the value “hi” in the main thread -and printing it + The receiver has two useful methods: `recv` and `try_recv`. We’re using `recv`, short for *receive*, which will block the main thread’s execution and wait @@ -139,14 +137,13 @@ problems: we’ll try to use a `val` value in the spawned thread *after* we’ve sent it down the channel. Try compiling the code in Listing 16-9 to see why this code isn’t allowed: -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-09/src/main.rs}} ``` -Listing 16-9: Attempting to use `val` after we’ve sent it -down the channel + Here, we try to print `val` after we’ve sent it down the channel via `tx.send`. Allowing this would be a bad idea: once the value has been sent to another @@ -172,14 +169,13 @@ two separate threads were talking to each other over the channel. In Listing running concurrently: the spawned thread will now send multiple messages and pause for a second between each message. -Filename: src/main.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-10/src/main.rs}} ``` -Listing 16-10: Sending multiple messages and pausing -between each + This time, the spawned thread has a vector of strings that we want to send to the main thread. We iterate over them, sending each individually, and pause @@ -215,14 +211,13 @@ single consumer*. Let’s put `mpsc` to use and expand the code in Listing 16-10 to create multiple threads that all send values to the same receiver. We can do so by cloning the transmitter, as shown in Listing 16-11: -Filename: src/main.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-11/src/main.rs:here}} ``` -Listing 16-11: Sending multiple messages from multiple -producers + This time, before we create the first spawned thread, we call `clone` on the transmitter. This will give us a new transmitter we can pass to the first diff --git a/rustbook-en/src/ch16-03-shared-state.md b/rustbook-en/src/ch16-03-shared-state.md index a5f806c5b..d319c6d6c 100644 --- a/rustbook-en/src/ch16-03-shared-state.md +++ b/rustbook-en/src/ch16-03-shared-state.md @@ -52,14 +52,13 @@ system and ownership rules, you can’t get locking and unlocking wrong. As an example of how to use a mutex, let’s start by using a mutex in a single-threaded context, as shown in Listing 16-12: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-12/src/main.rs}} ``` -Listing 16-12: Exploring the API of `Mutex` in a -single-threaded context for simplicity + As with many types, we create a `Mutex` using the associated function `new`. To access the data inside the mutex, we use the `lock` method to acquire the @@ -98,14 +97,13 @@ the counter goes from 0 to 10. The next example in Listing 16-13 will have a compiler error, and we’ll use that error to learn more about using `Mutex` and how Rust helps us use it correctly. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-13/src/main.rs}} ``` -Listing 16-13: Ten threads each increment a counter -guarded by a `Mutex` + We create a `counter` variable to hold an `i32` inside a `Mutex`, as we did in Listing 16-12. Next, we create 10 threads by iterating over a range of @@ -138,14 +136,13 @@ In Chapter 15, we gave a value multiple owners by using the smart pointer what happens. We’ll wrap the `Mutex` in `Rc` in Listing 16-14 and clone the `Rc` before moving ownership to the thread. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-14/src/main.rs}} ``` -Listing 16-14: Attempting to use `Rc` to allow -multiple threads to own the `Mutex` + Once again, we compile and get... different errors! The compiler is teaching us a lot. @@ -191,14 +188,13 @@ Let’s return to our example: `Arc` and `Rc` have the same API, so we fix our program by changing the `use` line, the call to `new`, and the call to `clone`. The code in Listing 16-15 will finally compile and run: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-15/src/main.rs}} ``` -Listing 16-15: Using an `Arc` to wrap the `Mutex` -to be able to share ownership across multiple threads + This code will print the following: diff --git a/rustbook-en/src/ch17-03-more-futures.md b/rustbook-en/src/ch17-03-more-futures.md index fecb73d03..5a9fea448 100644 --- a/rustbook-en/src/ch17-03-more-futures.md +++ b/rustbook-en/src/ch17-03-more-futures.md @@ -476,10 +476,10 @@ The version with `yield_now` is *way* faster! This means that async can be useful even for compute-bound tasks, depending on what else your program is doing, because it provides a useful tool for structuring the relationships between different parts of the program. This is a -form of *cooperative multitasking*, where each future has both the power to -determine when it hands over control via await points. Each future therefore -also has the responsibility to avoid blocking for too long. In some Rust-based -embedded operating systems, this is the *only* kind of multitasking! +form of *cooperative multitasking*, where each future has the power to determine +when it hands over control via await points. Each future therefore also has the +responsibility to avoid blocking for too long. In some Rust-based embedded +operating systems, this is the *only* kind of multitasking! In real-world code, you won’t usually be alternating function calls with await points on every single line, of course. While yielding control in this way is diff --git a/rustbook-en/src/ch17-04-streams.md b/rustbook-en/src/ch17-04-streams.md index a3085aa62..0000ac9c8 100644 --- a/rustbook-en/src/ch17-04-streams.md +++ b/rustbook-en/src/ch17-04-streams.md @@ -177,7 +177,7 @@ indicates a message arrived in time; the `Err` variant indicates that the timeout elapsed before any message arrived. We `match` on that result and either print the message when we receive it successfully, or print a notice about the timeout. Finally, notice that we pin the messages after applying the timeout to -them, because the timeout helper produces a future which needs to be pinned to +them, because the timeout helper produces a stream which needs to be pinned to be polled. diff --git a/rustbook-en/src/ch17-05-traits-for-async.md b/rustbook-en/src/ch17-05-traits-for-async.md index c7c82d871..07ed8c0db 100644 --- a/rustbook-en/src/ch17-05-traits-for-async.md +++ b/rustbook-en/src/ch17-05-traits-for-async.md @@ -115,9 +115,7 @@ it is not yet ready. ### Pinning and the Pin and Unpin Traits - - -When we introduced the idea of pinning, while working on Listing 17-17, we ran +When we introduced the idea of pinning while working on Listing 17-17, we ran into a very gnarly error message. Here is the relevant part of it again: