diff --git a/src/ch18-01-what-is-oo.md b/src/ch18-01-what-is-oo.md index f9f22a3a00..8e81826b9e 100644 --- a/src/ch18-01-what-is-oo.md +++ b/src/ch18-01-what-is-oo.md @@ -44,15 +44,13 @@ on demand whenever anyone needs it. In other words, `AveragedCollection` will cache the calculated average for us. Listing 18-1 has the definition of the `AveragedCollection` struct: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-01/src/lib.rs}} ``` -Listing 18-1: An `AveragedCollection` struct that -maintains a list of integers and the average of the items in the -collection + The struct is marked `pub` so that other code can use it, but the fields within the struct remain private. This is important in this case because we want to @@ -60,14 +58,15 @@ ensure that whenever a value is added or removed from the list, the average is also updated. We do this by implementing `add`, `remove`, and `average` methods on the struct, as shown in Listing 18-2: ++ Filename: src/lib.rs ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-02/src/lib.rs:here}} ``` -Listing 18-2: Implementations of the public methods -`add`, `remove`, and `average` on `AveragedCollection` + The public methods `add`, `remove`, and `average` are the only ways to access or modify data in an instance of `AveragedCollection`. When an item is added diff --git a/src/ch18-02-trait-objects.md b/src/ch18-02-trait-objects.md index 751fdaa033..6f05a4e0df 100644 --- a/src/ch18-02-trait-objects.md +++ b/src/ch18-02-trait-objects.md @@ -66,13 +66,13 @@ behavior. Listing 18-3 shows how to define a trait named `Draw` with one method named `draw`: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-03/src/lib.rs}} ``` -Listing 18-3: Definition of the `Draw` trait + This syntax should look familiar from our discussions on how to define traits in Chapter 10. Next comes some new syntax: Listing 18-4 defines a struct named @@ -80,27 +80,24 @@ in Chapter 10. Next comes some new syntax: Listing 18-4 defines a struct named `Box`, which is a trait object; it’s a stand-in for any type inside a `Box` that implements the `Draw` trait. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-04/src/lib.rs:here}} ``` -Listing 18-4: Definition of the `Screen` struct with a -`components` field holding a vector of trait objects that implement the `Draw` -trait + On the `Screen` struct, we’ll define a method named `run` that will call the `draw` method on each of its `components`, as shown in Listing 18-5: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-05/src/lib.rs:here}} ``` -Listing 18-5: A `run` method on `Screen` that calls the -`draw` method on each component + This works differently from defining a struct that uses a generic type parameter with trait bounds. A generic type parameter can only be substituted @@ -109,14 +106,13 @@ concrete types to fill in for the trait object at runtime. For example, we could have defined the `Screen` struct using a generic type and a trait bound as in Listing 18-6: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-06/src/lib.rs:here}} ``` -Listing 18-6: An alternate implementation of the `Screen` -struct and its `run` method using generics and trait bounds + This restricts us to a `Screen` instance that has a list of components all of type `Button` or all of type `TextField`. If you’ll only ever have homogeneous @@ -136,14 +132,13 @@ of this book, so the `draw` method won’t have any useful implementation in its body. To imagine what the implementation might look like, a `Button` struct might have fields for `width`, `height`, and `label`, as shown in Listing 18-7: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-07/src/lib.rs:here}} ``` -Listing 18-7: A `Button` struct that implements the -`Draw` trait + The `width`, `height`, and `label` fields on `Button` will differ from the fields on other components; for example, a `TextField` type might have those @@ -159,14 +154,13 @@ If someone using our library decides to implement a `SelectBox` struct that has `width`, `height`, and `options` fields, they implement the `Draw` trait on the `SelectBox` type as well, as shown in Listing 18-8: -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch18-oop/listing-18-08/src/main.rs:here}} ``` -Listing 18-8: Another crate using `gui` and implementing -the `Draw` trait on a `SelectBox` struct + Our library’s user can now write their `main` function to create a `Screen` instance. To the `Screen` instance, they can add a `SelectBox` and a `Button` @@ -174,14 +168,13 @@ by putting each in a `Box` to become a trait object. They can then call the `run` method on the `Screen` instance, which will call `draw` on each of the components. Listing 18-9 shows this implementation: -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch18-oop/listing-18-09/src/main.rs:here}} ``` -Listing 18-9: Using trait objects to store values of -different types that implement the same trait + When we wrote the library, we didn’t know that someone might add the `SelectBox` type, but our `Screen` implementation was able to operate on the @@ -208,14 +201,13 @@ our code if the values don’t implement the traits that the trait objects need. For example, Listing 18-10 shows what happens if we try to create a `Screen` with a `String` as a component: -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch18-oop/listing-18-10/src/main.rs}} ``` -Listing 18-10: Attempting to use a type that doesn’t -implement the trait object’s trait + We’ll get this error because `String` doesn’t implement the `Draw` trait: diff --git a/src/ch18-03-oo-design-patterns.md b/src/ch18-03-oo-design-patterns.md index 9a73091cda..683528c5db 100644 --- a/src/ch18-03-oo-design-patterns.md +++ b/src/ch18-03-oo-design-patterns.md @@ -40,14 +40,13 @@ Listing 18-11 shows this workflow in code form: this is an example usage of the API we’ll implement in a library crate named `blog`. This won’t compile yet because we haven’t implemented the `blog` crate. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch18-oop/listing-18-11/src/main.rs:all}} ``` -Listing 18-11: Code that demonstrates the desired -behavior we want our `blog` crate to have + We want to allow the user to create a new draft blog post with `Post::new`. We want to allow text to be added to the blog post. If we try to get the post’s @@ -84,15 +83,13 @@ Then `Post` will hold a trait object of `Box` inside an `Option` in a private field named `state` to hold the state object. You’ll see why the `Option` is necessary in a bit. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-12/src/lib.rs}} ``` -Listing 18-12: Definition of a `Post` struct and a `new` -function that creates a new `Post` instance, a `State` trait, and a `Draft` -struct + The `State` trait defines the behavior shared by different post states. The state objects are `Draft`, `PendingReview`, and `Published`, and they will all @@ -117,14 +114,13 @@ the `content` field’s data is read. The `add_text` method is pretty straightforward, so let’s add the implementation in Listing 18-13 to the `impl Post` block: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-13/src/lib.rs:here}} ``` -Listing 18-13: Implementing the `add_text` method to add -text to a post’s `content` + The `add_text` method takes a mutable reference to `self`, because we’re changing the `Post` instance that we’re calling `add_text` on. We then call @@ -145,14 +141,13 @@ once we implement the ability to change a post’s state so it can be published. So far, posts can only be in the draft state, so the post content should always be empty. Listing 18-14 shows this placeholder implementation: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-14/src/lib.rs:here}} ``` -Listing 18-14: Adding a placeholder implementation for -the `content` method on `Post` that always returns an empty string slice + With this added `content` method, everything in Listing 18-11 up to line 7 works as intended. @@ -162,14 +157,13 @@ works as intended. Next, we need to add functionality to request a review of a post, which should change its state from `Draft` to `PendingReview`. Listing 18-15 shows this code: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-15/src/lib.rs:here}} ``` -Listing 18-15: Implementing `request_review` methods on -`Post` and the `State` trait + We give `Post` a public method named `request_review` that will take a mutable reference to `self`. Then we call an internal `request_review` method on the @@ -222,14 +216,13 @@ The `approve` method will be similar to the `request_review` method: it will set `state` to the value that the current state says it should have when that state is approved, as shown in Listing 18-16: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-16/src/lib.rs:here}} ``` -Listing 18-16: Implementing the `approve` method on -`Post` and the `State` trait + We add the `approve` method to the `State` trait and add a new struct that implements `State`, the `Published` state. @@ -247,14 +240,13 @@ returned from `content` to depend on the current state of the `Post`, so we’re going to have the `Post` delegate to a `content` method defined on its `state`, as shown in Listing 18-17: -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch18-oop/listing-18-17/src/lib.rs:here}} ``` -Listing 18-17: Updating the `content` method on `Post` to -delegate to a `content` method on `State` + Because the goal is to keep all these rules inside the structs that implement `State`, we call a `content` method on the value in `state` and pass the post @@ -282,14 +274,13 @@ we need to add `content` to the `State` trait definition, and that is where we’ll put the logic for what content to return depending on which state we have, as shown in Listing 18-18: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-18/src/lib.rs:here}} ``` -Listing 18-18: Adding the `content` method to the `State` -trait + We add a default implementation for the `content` method that returns an empty string slice. That means we don’t need to implement `content` on the `Draft` @@ -383,12 +374,14 @@ draft posts where only published posts are allowed by issuing a compiler error. Let’s consider the first part of `main` in Listing 18-11: -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch18-oop/listing-18-11/src/main.rs:here}} ``` + + We still enable the creation of new posts in the draft state using `Post::new` and the ability to add text to the post’s content. But instead of having a `content` method on a draft post that returns an empty string, we’ll make it so @@ -399,14 +392,13 @@ display draft post content in production, because that code won’t even compile Listing 18-19 shows the definition of a `Post` struct and a `DraftPost` struct, as well as methods on each: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-19/src/lib.rs}} ``` -Listing 18-19: A `Post` with a `content` method and a -`DraftPost` without a `content` method + Both the `Post` and `DraftPost` structs have a private `content` field that stores the blog post text. The structs no longer have the `state` field because @@ -435,15 +427,13 @@ these constraints by adding another struct, `PendingReviewPost`, defining the defining an `approve` method on `PendingReviewPost` to return a `Post`, as shown in Listing 18-20: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch18-oop/listing-18-20/src/lib.rs:here}} ``` -Listing 18-20: A `PendingReviewPost` that gets created by -calling `request_review` on `DraftPost` and an `approve` method that turns a -`PendingReviewPost` into a published `Post` + The `request_review` and `approve` methods take ownership of `self`, thus consuming the `DraftPost` and `PendingReviewPost` instances and transforming @@ -465,14 +455,13 @@ pending review posts’ contents be empty strings, nor do we need them: we can compile code that tries to use the content of posts in those states any longer. The updated code in `main` is shown in Listing 18-21: -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch18-oop/listing-18-21/src/main.rs}} ``` -Listing 18-21: Modifications to `main` to use the new -implementation of the blog post workflow + The changes we needed to make to `main` to reassign `post` mean that this implementation doesn’t quite follow the object-oriented state pattern anymore: diff --git a/src/ch19-01-all-the-places-for-patterns.md b/src/ch19-01-all-the-places-for-patterns.md index 92578802e5..30e7135c53 100644 --- a/src/ch19-01-all-the-places-for-patterns.md +++ b/src/ch19-01-all-the-places-for-patterns.md @@ -63,14 +63,13 @@ a series of checks for several conditions. For this example, we’ve created variables with hardcoded values that a real program might receive from user input. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-01/src/main.rs}} ``` -Listing 19-1: Mixing `if let`, `else if`, `else if let`, -and `else` + If the user specifies a favorite color, that color is used as the background. If no favorite color is specified and today is Tuesday, the background color is @@ -103,12 +102,13 @@ Similar in construction to `if let`, the `while let` conditional loop allows a 19-2 we code a `while let` loop that uses a vector as a stack and prints the values in the vector in the opposite order in which they were pushed. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-02/src/main.rs:here}} ``` -Listing 19-2: Using a `while let` loop to print values -for as long as `stack.pop()` returns `Some` + This example prints 3, 2, and then 1. The `pop` method takes the last element out of the vector and returns `Some(value)`. If the vector is empty, `pop` @@ -123,12 +123,13 @@ pattern. For example, in `for x in y` the `x` is the pattern. Listing 19-3 demonstrates how to use a pattern in a `for` loop to destructure, or break apart, a tuple as part of the `for` loop. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-03/src/main.rs:here}} ``` -Listing 19-3: Using a pattern in a `for` loop to -destructure a tuple + The code in Listing 19-3 will print the following: @@ -171,12 +172,13 @@ effectively means “bind everything to the variable `x`, whatever the value is. To see the pattern matching aspect of `let` more clearly, consider Listing 19-4, which uses a pattern with `let` to destructure a tuple. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-04/src/main.rs:here}} ``` -Listing 19-4: Using a pattern to destructure a tuple and -create three variables at once + Here, we match a tuple against a pattern. Rust compares the value `(1, 2, 3)` to the pattern `(x, y, z)` and sees that the value matches the pattern, so Rust @@ -188,12 +190,13 @@ in the tuple, the overall type won’t match and we’ll get a compiler error. F example, Listing 19-5 shows an attempt to destructure a tuple with three elements into two variables, which won’t work. ++ ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-05/src/main.rs:here}} ``` -Listing 19-5: Incorrectly constructing a pattern whose -variables don’t match the number of elements in the tuple + Attempting to compile this code results in this type error: @@ -214,25 +217,25 @@ Function parameters can also be patterns. The code in Listing 19-6, which declares a function named `foo` that takes one parameter named `x` of type `i32`, should by now look familiar. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-06/src/main.rs:here}} ``` -Listing 19-6: A function signature uses patterns in the -parameters + The `x` part is a pattern! As we did with `let`, we could match a tuple in a function’s arguments to the pattern. Listing 19-7 splits the values in a tuple as we pass it to a function. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-07/src/main.rs}} ``` -Listing 19-7: A function with parameters that destructure -a tuple + This code prints `Current location: (3, 5)`. The values `&(3, 5)` match the pattern `&(x, y)`, so `x` is the value `3` and `y` is the value `5`. diff --git a/src/ch19-02-refutability.md b/src/ch19-02-refutability.md index a648d46a17..3601f5d14f 100644 --- a/src/ch19-02-refutability.md +++ b/src/ch19-02-refutability.md @@ -27,12 +27,13 @@ where Rust requires an irrefutable pattern and vice versa. Listing 19-8 shows a `let` statement, but for the pattern we’ve specified `Some(x)`, a refutable pattern. As you might expect, this code will not compile. ++ ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-08/src/main.rs:here}} ``` -Listing 19-8: Attempting to use a refutable pattern with -`let` + If `some_option_value` was a `None` value, it would fail to match the pattern `Some(x)`, meaning the pattern is refutable. However, the `let` statement can @@ -53,24 +54,26 @@ can use `if let`. Then if the pattern doesn’t match, the code will just skip the code in the curly brackets, giving it a way to continue validly. Listing 19-9 shows how to fix the code in Listing 19-8. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-09/src/main.rs:here}} ``` -Listing 19-9: Using `if let` and a block with refutable -patterns instead of `let` + We’ve given the code an out! This code is perfectly valid now. However, if we give `if let` an irrefutable pattern (a pattern that will always match), such as `x`, as shown in Listing 19-10, the compiler will give a warning. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-10/src/main.rs:here}} ``` -Listing 19-10: Attempting to use an irrefutable pattern -with `if let` + Rust complains that it doesn’t make sense to use `if let` with an irrefutable pattern: diff --git a/src/ch19-03-pattern-syntax.md b/src/ch19-03-pattern-syntax.md index afdcc4246d..4a471bd670 100644 --- a/src/ch19-03-pattern-syntax.md +++ b/src/ch19-03-pattern-syntax.md @@ -29,14 +29,13 @@ value `Some(5)` and a variable `y` with the value `10`. We then create a `println!` at the end, and try to figure out what the code will print before running this code or reading further. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-11/src/main.rs:here}} ``` -Listing 19-11: A `match` expression with an arm that -introduces a shadowed variable `y` + Let’s walk through what happens when the `match` expression runs. The pattern in the first match arm doesn’t match the defined value of `x`, so the code @@ -119,14 +118,13 @@ different parts of these values. Let’s walk through each value. Listing 19-12 shows a `Point` struct with two fields, `x` and `y`, that we can break apart using a pattern with a `let` statement. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-12/src/main.rs}} ``` -Listing 19-12: Destructuring a struct’s fields into -separate variables + This code creates the variables `a` and `b` that match the values of the `x` and `y` fields of the `p` struct. This example shows that the names of the @@ -140,14 +138,13 @@ from the pattern will have the same names. Listing 19-13 behaves in the same way as the code in Listing 19-12, but the variables created in the `let` pattern are `x` and `y` instead of `a` and `b`. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-13/src/main.rs}} ``` -Listing 19-13: Destructuring struct fields using struct -field shorthand + This code creates the variables `x` and `y` that match the `x` and `y` fields of the `p` variable. The outcome is that the variables `x` and `y` contain the @@ -162,14 +159,13 @@ In Listing 19-14, we have a `match` expression that separates `Point` values into three cases: points that lie directly on the `x` axis (which is true when `y = 0`), on the `y` axis (`x = 0`), or neither. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-14/src/main.rs:here}} ``` -Listing 19-14: Destructuring and matching literal values -in one pattern + The first arm will match any point that lies on the `x` axis by specifying that the `y` field matches if its value matches the literal `0`. The pattern still @@ -195,14 +191,13 @@ corresponds to the way the data stored within the enum is defined. As an example, in Listing 19-15 we use the `Message` enum from Listing 6-2 and write a `match` with patterns that will destructure each inner value. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-15/src/main.rs}} ``` -Listing 19-15: Destructuring enum variants that hold -different kinds of values + This code will print `Change the color to red 0, green 160, and blue 255`. Try changing the value of `msg` to see the code from the other arms run. @@ -230,11 +225,13 @@ but matching can work on nested items too! For example, we can refactor the code in Listing 19-15 to support RGB and HSV colors in the `ChangeColor` message, as shown in Listing 19-16. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-16/src/main.rs}} ``` -Listing 19-16: Matching on nested enums + The pattern of the first arm in the `match` expression matches a `Message::ChangeColor` enum variant that contains a `Color::Rgb` variant; then @@ -276,13 +273,13 @@ not bind to the value. This is especially useful as the last arm in a `match` expression, but we can also use it in any pattern, including function parameters, as shown in Listing 19-17. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-17/src/main.rs}} ``` -Listing 19-17: Using `_` in a function signature + This code will completely ignore the value `3` passed as the first argument, and will print `This code only uses the y parameter: 4`. @@ -304,13 +301,13 @@ responsible for managing a setting’s value. The business requirements are that the user should not be allowed to overwrite an existing customization of a setting but can unset the setting and give it a value if it is currently unset. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-18/src/main.rs:here}} ``` -Listing 19-18: Using an underscore within patterns that -match `Some` variants when we don’t need to use the value inside the -`Some` + This code will print `Can't overwrite an existing customized value` and then `setting is Some(5)`. In the first match arm, we don’t need to match on or use @@ -327,11 +324,13 @@ We can also use underscores in multiple places within one pattern to ignore particular values. Listing 19-19 shows an example of ignoring the second and fourth values in a tuple of five items. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-19/src/main.rs:here}} ``` -Listing 19-19: Ignoring multiple parts of a tuple + This code will print `Some numbers: 2, 8, 32`, and the values 4 and 16 will be ignored. @@ -346,14 +345,13 @@ not to warn you about the unused variable by starting the name of the variable with an underscore. In Listing 19-20, we create two unused variables, but when we compile this code, we should only get a warning about one of them. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-20/src/main.rs}} ``` -Listing 19-20: Starting a variable name with an -underscore to avoid getting unused variable warnings + Here we get a warning about not using the variable `y`, but we don’t get a warning about not using `_x`. @@ -363,24 +361,26 @@ that starts with an underscore. The syntax `_x` still binds the value to the variable, whereas `_` doesn’t bind at all. To show a case where this distinction matters, Listing 19-21 will provide us with an error. ++ ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-21/src/main.rs:here}} ``` -Listing 19-21: An unused variable starting with an -underscore still binds the value, which might take ownership of the value + We’ll receive an error because the `s` value will still be moved into `_s`, which prevents us from using `s` again. However, using the underscore by itself doesn’t ever bind to the value. Listing 19-22 will compile without any errors because `s` doesn’t get moved into `_`. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-22/src/main.rs:here}} ``` -Listing 19-22: Using an underscore does not bind the -value + This code works just fine because we never bind `s` to anything; it isn’t moved. @@ -394,12 +394,13 @@ explicitly matched in the rest of the pattern. In Listing 19-23, we have a `match` expression, we want to operate only on the `x` coordinate and ignore the values in the `y` and `z` fields. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-23/src/main.rs:here}} ``` -Listing 19-23: Ignoring all fields of a `Point` except -for `x` by using `..` + We list the `x` value and then just include the `..` pattern. This is quicker than having to list `y: _` and `z: _`, particularly when we’re working with @@ -409,14 +410,13 @@ relevant. The syntax `..` will expand to as many values as it needs to be. Listing 19-24 shows how to use `..` with a tuple. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-24/src/main.rs}} ``` -Listing 19-24: Matching only the first and last values in -a tuple and ignoring all other values + In this code, the first and last value are matched with `first` and `last`. The `..` will match and ignore everything in the middle. @@ -426,14 +426,13 @@ intended for matching and which should be ignored, Rust will give us an error. Listing 19-25 shows an example of using `..` ambiguously, so it will not compile. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-25/src/main.rs}} ``` -Listing 19-25: An attempt to use `..` in an ambiguous -way + When we compile this example, we get this error: @@ -459,11 +458,13 @@ The condition can use variables created in the pattern. Listing 19-26 shows a `match` where the first arm has the pattern `Some(x)` and also has a match guard of `if x % 2 == 0` (which will be true if the number is even). ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-26/src/main.rs:here}} ``` -Listing 19-26: Adding a match guard to a pattern + This example will print `The number 4 is even`. When `num` is compared to the pattern in the first arm, it matches, because `Some(4)` matches `Some(x)`. Then @@ -487,14 +488,13 @@ pattern in the `match` expression instead of using the variable outside the outer variable. Listing 19-27 shows how we can use a match guard to fix this problem. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-27/src/main.rs}} ``` -Listing 19-27: Using a match guard to test for equality -with an outer variable + This code will now print `Default case, x = Some(5)`. The pattern in the second match arm doesn’t introduce a new variable `y` that would shadow the outer `y`, @@ -515,12 +515,13 @@ guard. The important part of this example is that the `if y` match guard applies to `4`, `5`, *and* `6`, even though it might look like `if y` only applies to `6`. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-28/src/main.rs:here}} ``` -Listing 19-28: Combining multiple patterns with a match -guard + The match condition states that the arm only matches if the value of `x` is equal to `4`, `5`, or `6` *and* if `y` is `true`. When this code runs, the @@ -555,12 +556,13 @@ want to bind the value to the variable `id_variable` so we can use it in the code associated with the arm. We could name this variable `id`, the same as the field, but for this example we’ll use a different name. ++ ```rust {{#rustdoc_include ../listings/ch19-patterns-and-matching/listing-19-29/src/main.rs:here}} ``` -Listing 19-29: Using `@` to bind to a value in a pattern -while also testing it + This example will print `Found an id in range: 5`. By specifying `id_variable @` before the range `3..=7`, we’re capturing whatever value matched the range diff --git a/src/ch20-01-unsafe-rust.md b/src/ch20-01-unsafe-rust.md index dfdef6c393..ae4e674f1e 100644 --- a/src/ch20-01-unsafe-rust.md +++ b/src/ch20-01-unsafe-rust.md @@ -91,11 +91,13 @@ interface with another language or hardware where Rust’s guarantees don’t ap Listing 20-1 shows how to create an immutable and a mutable raw pointer from references. ++ ```rust {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-01/src/main.rs:here}} ``` -Listing 20-1: Creating raw pointers from references + Notice that we don’t include the `unsafe` keyword in this code. We can create raw pointers in safe code; we just can’t dereference raw pointers outside an @@ -115,23 +117,25 @@ so there is no memory access, or the program might error with a segmentation fault. Usually, there is no good reason to write code like this, but it is possible. ++ ```rust {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-02/src/main.rs:here}} ``` -Listing 20-2: Creating a raw pointer to an arbitrary -memory address + Recall that we can create raw pointers in safe code, but we can’t *dereference* raw pointers and read the data being pointed to. In Listing 20-3, we use the dereference operator `*` on a raw pointer that requires an `unsafe` block. ++ ```rust {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-03/src/main.rs:here}} ``` -Listing 20-3: Dereferencing raw pointers within an -`unsafe` block + Creating a pointer does no harm; it’s only when we try to access the value that it points at that we might end up dealing with an invalid value. @@ -196,24 +200,26 @@ we might implement it. This safe method is defined on mutable slices: it takes one slice and makes it two by splitting the slice at the index given as an argument. Listing 20-4 shows how to use `split_at_mut`. ++ ```rust {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-04/src/main.rs:here}} ``` -Listing 20-4: Using the safe `split_at_mut` -function + We can’t implement this function using only safe Rust. An attempt might look something like Listing 20-5, which won’t compile. For simplicity, we’ll implement `split_at_mut` as a function rather than a method and only for slices of `i32` values rather than for a generic type `T`. ++ ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-05/src/main.rs:here}} ``` -Listing 20-5: An attempted implementation of -`split_at_mut` using only safe Rust + This function first gets the total length of the slice. Then it asserts that the index given as a parameter is within the slice by checking whether it’s @@ -240,12 +246,13 @@ know code is okay, but Rust doesn’t, it’s time to reach for unsafe code. Listing 20-6 shows how to use an `unsafe` block, a raw pointer, and some calls to unsafe functions to make the implementation of `split_at_mut` work. ++ ```rust {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-06/src/main.rs:here}} ``` -Listing 20-6: Using unsafe code in the implementation of -the `split_at_mut` function + Recall from [“The Slice Type”][the-slice-type] section in Chapter 4 that slices are a pointer to some data and the length of the slice. @@ -282,12 +289,13 @@ In contrast, the use of `slice::from_raw_parts_mut` in Listing 20-7 would likely crash when the slice is used. This code takes an arbitrary memory location and creates a slice 10,000 items long. ++ ```rust {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-07/src/main.rs:here}} ``` -Listing 20-7: Creating a slice from an arbitrary memory -location + We don’t own the memory at this arbitrary location, and there is no guarantee that the slice this code creates contains valid `i32` values. Attempting to use @@ -307,14 +315,13 @@ always unsafe to call from Rust code. The reason is that other languages don’t enforce Rust’s rules and guarantees, and Rust can’t check them, so responsibility falls on the programmer to ensure safety. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-08/src/main.rs}} ``` -Listing 20-8: Declaring and calling an `extern` function -defined in another language + Within the `extern "C"` block, we list the names and signatures of external functions from another language we want to call. The `"C"` part defines which @@ -357,14 +364,13 @@ In Rust, global variables are called *static* variables. Listing 20-9 shows an example declaration and use of a static variable with a string slice as a value. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-09/src/main.rs}} ``` -Listing 20-9: Defining and using an immutable static -variable + Static variables are similar to constants, which we discussed in the [“Differences Between Variables and @@ -383,14 +389,13 @@ variables can be mutable. Accessing and modifying mutable static variables is *unsafe*. Listing 20-10 shows how to declare, access, and modify a mutable static variable named `COUNTER`. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-10/src/main.rs}} ``` -Listing 20-10: Reading from or writing to a mutable -static variable is unsafe + As with regular variables, we specify mutability using the `mut` keyword. Any code that reads or writes from `COUNTER` must be within an `unsafe` block. This @@ -412,12 +417,13 @@ declare that a trait is `unsafe` by adding the `unsafe` keyword before `trait` and marking the implementation of the trait as `unsafe` too, as shown in Listing 20-11. ++ ```rust {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-11/src/main.rs}} ``` -Listing 20-11: Defining and implementing an unsafe -trait + By using `unsafe impl`, we’re promising that we’ll uphold the invariants that the compiler can’t verify. diff --git a/src/ch20-03-advanced-traits.md b/src/ch20-03-advanced-traits.md index 7dc333e782..e411dd57de 100644 --- a/src/ch20-03-advanced-traits.md +++ b/src/ch20-03-advanced-traits.md @@ -25,12 +25,13 @@ for the type of the values the type implementing the `Iterator` trait is iterating over. The definition of the `Iterator` trait is as shown in Listing 20-12. ++ ```rust,noplayground {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-12/src/lib.rs}} ``` -Listing 20-12: The definition of the `Iterator` trait -that has an associated type `Item` + The type `Item` is a placeholder, and the `next` method’s definition shows that it will return values of type `Option`. Implementors of the @@ -43,21 +44,24 @@ handle. To examine the difference between the two concepts, we’ll look at an implementation of the `Iterator` trait on a type named `Counter` that specifies the `Item` type is `u32`: -Filename: src/lib.rs + ```rust,ignore {{#rustdoc_include ../listings/ch20-advanced-features/no-listing-22-iterator-on-counter/src/lib.rs:ch19}} ``` + + This syntax seems comparable to that of generics. So why not just define the `Iterator` trait with generics, as shown in Listing 20-13? ++ ```rust,noplayground {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-13/src/lib.rs}} ``` -Listing 20-13: A hypothetical definition of the -`Iterator` trait using generics + The difference is that when using generics, as in Listing 20-13, we must annotate the types in each implementation; because we can also implement @@ -98,14 +102,13 @@ example, in Listing 20-14 we overload the `+` operator to add two `Point` instances together. We do this by implementing the `Add` trait on a `Point` struct: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-14/src/main.rs}} ``` -Listing 20-14: Implementing the `Add` trait to overload -the `+` operator for `Point` instances + The `add` method adds the `x` values of two `Point` instances and the `y` values of two `Point` instances to create a new `Point`. The `Add` trait has an @@ -144,14 +147,13 @@ Pattern to Implement External Traits on External Types”][newtype] diff --git a/src/ch20-05-advanced-functions-and-closures.md b/src/ch20-05-advanced-functions-and-closures.md index ef6a6e46f7..70385af324 100644 --- a/src/ch20-05-advanced-functions-and-closures.md +++ b/src/ch20-05-advanced-functions-and-closures.md @@ -22,14 +22,13 @@ function `f` twice, passing it the `arg` value, then adds the two function call results together. The `main` function calls `do_twice` with the arguments `add_one` and `5`. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-27/src/main.rs}} ``` -Listing 20-27: Using the `fn` type to accept a function -pointer as an argument + This code prints `The answer is: 12`. We specify that the parameter `f` in `do_twice` is an `fn` that takes one parameter of type `i32` and returns an diff --git a/src/ch20-06-macros.md b/src/ch20-06-macros.md index 2406942df2..7900a015bc 100644 --- a/src/ch20-06-macros.md +++ b/src/ch20-06-macros.md @@ -75,14 +75,13 @@ because we wouldn’t know the number or type of values up front. Listing 20-28 shows a slightly simplified definition of the `vec!` macro. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-28/src/lib.rs}} ``` -Listing 20-28: A simplified version of the `vec!` macro -definition + > Note: The actual definition of the `vec!` macro in the standard library > includes code to preallocate the correct amount of memory up front. That code @@ -164,7 +163,7 @@ to eliminate in the future. In Listing 20-29, we show how to define a procedural macro, where `some_attribute` is a placeholder for using a specific macro variety. -Filename: src/lib.rs + ```rust,ignore use proc_macro; @@ -174,8 +173,7 @@ pub fn some_name(input: TokenStream) -> TokenStream { } ``` -Listing 20-29: An example of defining a procedural -macro + The function that defines a procedural macro takes a `TokenStream` as an input and produces a `TokenStream` as an output. The `TokenStream` type is defined by @@ -202,14 +200,13 @@ TypeName!` where `TypeName` is the name of the type on which this trait has been defined. In other words, we’ll write a crate that enables another programmer to write code like Listing 20-30 using our crate. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-30/src/main.rs}} ``` -Listing 20-30: The code a user of our crate will be able -to write when using our procedural macro + This code will print `Hello, Macro! My name is Pancakes!` when we’re done. The first step is to make a new library crate, like this: @@ -220,12 +217,14 @@ $ cargo new hello_macro --lib Next, we’ll define the `HelloMacro` trait and its associated function: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch20-advanced-features/no-listing-20-impl-hellomacro-for-pancakes/hello_macro/src/lib.rs}} ``` + + We have a trait and its function. At this point, our crate user could implement the trait to achieve the desired functionality, like so: @@ -269,24 +268,25 @@ We’ll also need functionality from the `syn` and `quote` crates, as you’ll s in a moment, so we need to add them as dependencies. Add the following to the *Cargo.toml* file for `hello_macro_derive`: -Filename: hello_macro_derive/Cargo.toml + ```toml {{#include ../listings/ch20-advanced-features/listing-20-31/hello_macro/hello_macro_derive/Cargo.toml:6:12}} ``` + + To start defining the procedural macro, place the code in Listing 20-31 into your *src/lib.rs* file for the `hello_macro_derive` crate. Note that this code won’t compile until we add a definition for the `impl_hello_macro` function. -Filename: hello_macro_derive/src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-31/hello_macro/hello_macro_derive/src/lib.rs}} ``` -Listing 20-31: Code that most procedural macro crates -will require in order to process Rust code + Notice that we’ve split the code into the `hello_macro_derive` function, which is responsible for parsing the `TokenStream`, and the `impl_hello_macro` @@ -321,6 +321,8 @@ operations on. This is where `syn` comes into play. The `parse` function in parsed Rust code. Listing 20-32 shows the relevant parts of the `DeriveInput` struct we get from parsing the `struct Pancakes;` string: ++ ```rust,ignore DeriveInput { // --snip-- @@ -341,8 +343,7 @@ DeriveInput { } ``` -Listing 20-32: The `DeriveInput` instance we get when -parsing the code that has the macro’s attribute in Listing 20-30 + The fields of this struct show that the Rust code we’ve parsed is a unit struct with the `ident` (identifier, meaning the name) of `Pancakes`. There are more @@ -368,14 +369,13 @@ Now that we have the code to turn the annotated Rust code from a `TokenStream` into a `DeriveInput` instance, let’s generate the code that implements the `HelloMacro` trait on the annotated type, as shown in Listing 20-33. -Filename: hello_macro_derive/src/lib.rs + ```rust,ignore {{#rustdoc_include ../listings/ch20-advanced-features/listing-20-33/hello_macro/hello_macro_derive/src/lib.rs:here}} ``` -Listing 20-33: Implementing the `HelloMacro` trait using -the parsed Rust code + We get an `Ident` struct instance containing the name (identifier) of the annotated type using `ast.ident`. The struct in Listing 20-32 shows that when diff --git a/src/ch21-01-single-threaded.md b/src/ch21-01-single-threaded.md index 744a2a7829..9712b69a41 100644 --- a/src/ch21-01-single-threaded.md +++ b/src/ch21-01-single-threaded.md @@ -34,14 +34,13 @@ Now enter the code in Listing 21-1 in *src/main.rs* to start. This code will listen at the local address `127.0.0.1:7878` for incoming TCP streams. When it gets an incoming stream, it will print `Connection established!`. -Filename: src/main.rs + ```rust,no_run {{#rustdoc_include ../listings/ch21-web-server/listing-21-01/src/main.rs}} ``` -Listing 21-1: Listening for incoming streams and printing -a message when we receive a stream + Using `TcpListener`, we can listen for TCP connections at the address `127.0.0.1:7878`. In the address, the section before the colon is an IP address @@ -127,14 +126,13 @@ this new `handle_connection` function, we’ll read data from the TCP stream and print it so we can see the data being sent from the browser. Change the code to look like Listing 21-2. -Filename: src/main.rs + ```rust,no_run {{#rustdoc_include ../listings/ch21-web-server/listing-21-02/src/main.rs}} ``` -Listing 21-2: Reading from the `TcpStream` and printing -the data + We bring `std::io::prelude` and `std::io::BufReader` into scope to get access to traits and types that let us read from and write to the stream. In the `for` @@ -273,14 +271,13 @@ successful request! From the `handle_connection` function, remove the `println!` that was printing the request data and replace it with the code in Listing 21-3. -Filename: src/main.rs + ```rust,no_run {{#rustdoc_include ../listings/ch21-web-server/listing-21-03/src/main.rs:here}} ``` -Listing 21-3: Writing a tiny successful HTTP response to -the stream + The first new line defines the `response` variable that holds the success message’s data. Then we call `as_bytes` on our `response` to convert the string @@ -302,28 +299,26 @@ the new file *hello.html* in the root of your project directory, not in the *src* directory. You can input any HTML you want; Listing 21-4 shows one possibility. -Filename: hello.html + ```html {{#include ../listings/ch21-web-server/listing-21-05/hello.html}} ``` -Listing 21-4: A sample HTML file to return in a -response + This is a minimal HTML5 document with a heading and some text. To return this from the server when a request is received, we’ll modify `handle_connection` as shown in Listing 21-5 to read the HTML file, add it to the response as a body, and send it. -Filename: src/main.rs + ```rust,no_run {{#rustdoc_include ../listings/ch21-web-server/listing-21-05/src/main.rs:here}} ``` -Listing 21-5: Sending the contents of *hello.html* as the -body of the response + We’ve added `fs` to the `use` statement to bring the standard library’s filesystem module into scope. The code for reading the contents of a file to a @@ -356,14 +351,13 @@ as shown in Listing 21-6. This new code checks the content of the request received against what we know a request for */* looks like and adds `if` and `else` blocks to treat requests differently. -Filename: src/main.rs + ```rust,no_run {{#rustdoc_include ../listings/ch21-web-server/listing-21-06/src/main.rs:here}} ``` -Listing 21-6: Handling requests to */* differently from -other requests + We’re only going to be looking at the first line of the HTTP request, so rather than reading the entire request into a vector, we’re calling `next` to get the @@ -390,14 +384,13 @@ with the status code 404, which signals that the content for the request was not found. We’ll also return some HTML for a page to render in the browser indicating the response to the end user. -Filename: src/main.rs + ```rust,no_run {{#rustdoc_include ../listings/ch21-web-server/listing-21-07/src/main.rs:here}} ``` -Listing 21-7: Responding with status code 404 and an -error page if anything other than */* was requested + Here, our response has a status line with status code 404 and the reason phrase `NOT FOUND`. The body of the response will be the HTML in the file *404.html*. @@ -405,14 +398,13 @@ You’ll need to create a *404.html* file next to *hello.html* for the error page; again feel free to use any HTML you want or use the example HTML in Listing 21-8. -Filename: 404.html + ```html {{#include ../listings/ch21-web-server/listing-21-07/404.html}} ``` -Listing 21-8: Sample content for the page to send back -with any 404 response + With these changes, run your server again. Requesting *127.0.0.1:7878* should return the contents of *hello.html*, and any other request, like @@ -429,14 +421,13 @@ we can then use those variables unconditionally in the code to read the file and write the response. Listing 21-9 shows the resulting code after replacing the large `if` and `else` blocks. -Filename: src/main.rs + ```rust,no_run {{#rustdoc_include ../listings/ch21-web-server/listing-21-09/src/main.rs:here}} ``` -Listing 21-9: Refactoring the `if` and `else` blocks to -contain only the code that differs between the two cases + Now the `if` and `else` blocks only return the appropriate values for the status line and filename in a tuple; we then use destructuring to assign these diff --git a/src/ch21-02-multithreaded.md b/src/ch21-02-multithreaded.md index 4204693508..c4220a7bf5 100644 --- a/src/ch21-02-multithreaded.md +++ b/src/ch21-02-multithreaded.md @@ -15,14 +15,13 @@ our current server implementation. Listing 21-10 implements handling a request to */sleep* with a simulated slow response that will cause the server to sleep for 5 seconds before responding. -Filename: src/main.rs + ```rust,no_run {{#rustdoc_include ../listings/ch21-web-server/listing-21-10/src/main.rs:here}} ``` -Listing 21-10: Simulating a slow request by sleeping for -5 seconds + We switched from `if` to `match` now that we have three cases. We need to explicitly match on a slice of `request_line` to pattern match against the @@ -106,14 +105,13 @@ thread pool as an improvement, and contrasting the two solutions will be easier. Listing 21-11 shows the changes to make to `main` to spawn a new thread to handle each stream within the `for` loop. -Filename: src/main.rs + ```rust,no_run {{#rustdoc_include ../listings/ch21-web-server/listing-21-11/src/main.rs:here}} ``` -Listing 21-11: Spawning a new thread for each -stream + As you learned in Chapter 16, `thread::spawn` will create a new thread and then run the code in the closure in the new thread. If you run this code and load @@ -132,13 +130,13 @@ threads to a thread pool doesn’t require large changes to the code that uses our API. Listing 21-12 shows the hypothetical interface for a `ThreadPool` struct we want to use instead of `thread::spawn`. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch21-web-server/listing-21-12/src/main.rs:here}} ``` -Listing 21-12: Our ideal `ThreadPool` interface + We use `ThreadPool::new` to create a new thread pool with a configurable number of threads, in this case four. Then, in the `for` loop, `pool.execute` has a @@ -171,21 +169,25 @@ web requests. Create a *src/lib.rs* that contains the following, which is the simplest definition of a `ThreadPool` struct that we can have for now: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch21-web-server/no-listing-01-define-threadpool-struct/src/lib.rs}} ``` + + Then edit *main.rs* file to bring `ThreadPool` into scope from the library crate by adding the following code to the top of *src/main.rs*: -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch21-web-server/no-listing-01-define-threadpool-struct/src/main.rs:here}} ``` + + This code still won’t work, but let’s check it again to get the next error that we need to address: @@ -199,12 +201,14 @@ that can accept `4` as an argument and should return a `ThreadPool` instance. Let’s implement the simplest `new` function that will have those characteristics: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch21-web-server/no-listing-02-impl-threadpool-new/src/lib.rs}} ``` + + We chose `usize` as the type of the `size` parameter, because we know that a negative number of threads doesn’t make any sense. We also know we’ll use this 4 as the number of elements in a collection of threads, which is what the @@ -255,12 +259,14 @@ closure from one thread to another and `'static` because we don’t know how lon the thread will take to execute. Let’s create an `execute` method on `ThreadPool` that will take a generic parameter of type `F` with these bounds: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch21-web-server/no-listing-03-define-execute/src/lib.rs:here}} ``` + + We still use the `()` after `FnOnce` because this `FnOnce` represents a closure that takes no parameters and returns the unit type `()`. Just like function definitions, the return type can be omitted from the signature, but even if we @@ -296,14 +302,13 @@ valid `usize`. We’ll add code to check that `size` is greater than zero before we return a `ThreadPool` instance and have the program panic if it receives a zero by using the `assert!` macro, as shown in Listing 21-13. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch21-web-server/listing-21-13/src/lib.rs:here}} ``` -Listing 21-13: Implementing `ThreadPool::new` to panic if -`size` is zero + We’ve also added some documentation for our `ThreadPool` with doc comments. Note that we followed good documentation practices by adding a section that @@ -348,14 +353,13 @@ We’ve changed the definition of `ThreadPool` to hold a vector of `size`, set up a `for` loop that will run some code to create the threads, and returned a `ThreadPool` instance containing them. -Filename: src/lib.rs + ```rust,ignore,not_desired_behavior {{#rustdoc_include ../listings/ch21-web-server/listing-21-14/src/lib.rs:here}} ``` -Listing 21-14: Creating a vector for `ThreadPool` to hold -the threads + We’ve brought `std::thread` into scope in the library crate, because we’re using `thread::JoinHandle` as the type of the items in the vector in @@ -413,14 +417,13 @@ looking at the code in Listing 21-15. Ready? Here is Listing 21-15 with one way to make the preceding modifications. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch21-web-server/listing-21-15/src/lib.rs:here}} ``` -Listing 21-15: Modifying `ThreadPool` to hold `Worker` -instances instead of holding threads directly + We’ve changed the name of the field on `ThreadPool` from `threads` to `workers` because it’s now holding `Worker` instances instead of `JoinHandle<()>` @@ -474,14 +477,13 @@ in the `ThreadPool` instance, as shown in Listing 21-16. The `Job` struct doesn’t hold anything for now but will be the type of item we’re sending down the channel. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch21-web-server/listing-21-16/src/lib.rs:here}} ``` -Listing 21-16: Modifying `ThreadPool` to store the -sender of a channel that transmits `Job` instances + In `ThreadPool::new`, we create our new channel and have the pool hold the sender. This will successfully compile. @@ -491,13 +493,13 @@ creates the channel. We know we want to use the receiver in the thread that the workers spawn, so we’ll reference the `receiver` parameter in the closure. The code in Listing 21-17 won’t quite compile yet. -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch21-web-server/listing-21-17/src/lib.rs:here}} ``` -Listing 21-17: Passing the receiver to the workers + We’ve made some small and straightforward changes: we pass the receiver into `Worker::new`, and then we use it inside the closure. @@ -525,14 +527,13 @@ need to use `Arc>`. The `Arc` type will let multiple workers own the receiver, and `Mutex` will ensure that only one worker gets a job from the receiver at a time. Listing 21-18 shows the changes we need to make. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch21-web-server/listing-21-18/src/lib.rs:here}} ``` -Listing 21-18: Sharing the receiver among the workers -using `Arc` and `Mutex` + In `ThreadPool::new`, we put the receiver in an `Arc` and a `Mutex`. For each new worker, we clone the `Arc` to bump the reference count so the workers can @@ -549,14 +550,13 @@ with Type Aliases”][creating-type-synonyms-with-type-aliases] section of Chapter 20, type aliases allow us to make long types shorter for ease of use. Look at Listing 21-19. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch21-web-server/listing-21-19/src/lib.rs:here}} ``` -Listing 21-19: Creating a `Job` type alias for a `Box` -that holds each closure and then sending the job down the channel + After creating a new `Job` instance using the closure we get in `execute`, we send that job down the sending end of the channel. We’re calling `unwrap` on @@ -573,14 +573,13 @@ Instead, we need the closure to loop forever, asking the receiving end of the channel for a job and running the job when it gets one. Let’s make the change shown in Listing 21-20 to `Worker::new`. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch21-web-server/listing-21-20/src/lib.rs:here}} ``` -Listing 21-20: Receiving and executing the jobs in the -worker’s thread + Here, we first call `lock` on the `receiver` to acquire the mutex, and then we call `unwrap` to panic on any errors. Acquiring a lock might fail if the mutex @@ -661,14 +660,13 @@ thread run them. After learning about the `while let` loop in Chapters 17 and 18, you might be wondering why we didn’t write the worker thread code as shown in Listing 21-21. -Filename: src/lib.rs + ```rust,ignore,not_desired_behavior {{#rustdoc_include ../listings/ch21-web-server/listing-21-21/src/lib.rs:here}} ``` -Listing 21-21: An alternative implementation of -`Worker::new` using `while let` + This code compiles and runs but doesn’t result in the desired threading behavior: a slow request will still cause other requests to wait to be diff --git a/src/ch21-03-graceful-shutdown-and-cleanup.md b/src/ch21-03-graceful-shutdown-and-cleanup.md index 24a8aabf6f..e73c4a5a59 100644 --- a/src/ch21-03-graceful-shutdown-and-cleanup.md +++ b/src/ch21-03-graceful-shutdown-and-cleanup.md @@ -22,14 +22,13 @@ dropped, our threads should all join to make sure they finish their work. Listing 21-22 shows a first attempt at a `Drop` implementation; this code won’t quite work yet. -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch21-web-server/listing-21-22/src/lib.rs:here}} ``` -Listing 21-22: Joining each thread when the thread pool -goes out of scope + First, we loop through each of the thread pool `workers`. We use `&mut` for this because `self` is a mutable reference, and we also need to be able to @@ -57,12 +56,14 @@ thread to run. So we know we want to update the definition of `Worker` like this: -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch21-web-server/no-listing-04-update-worker-definition/src/lib.rs:here}} ``` + + Now let’s lean on the compiler to find the other places that need to change. Checking this code, we get two errors: @@ -74,22 +75,26 @@ Let’s address the second error, which points to the code at the end of `Worker::new`; we need to wrap the `thread` value in `Some` when we create a new `Worker`. Make the following changes to fix this error: -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch21-web-server/no-listing-05-fix-worker-new/src/lib.rs:here}} ``` + + The first error is in our `Drop` implementation. We mentioned earlier that we intended to call `take` on the `Option` value to move `thread` out of `worker`. The following changes will do so: -Filename: src/lib.rs + ```rust,ignore,not_desired_behavior {{#rustdoc_include ../listings/ch21-web-server/no-listing-06-fix-threadpool-drop/src/lib.rs:here}} ``` + + As discussed in Chapter 18, the `take` method on `Option` takes the `Some` variant out and leaves `None` in its place. We’re using `if let` to destructure the `Some` and get the thread; then we call `join` on the thread. If a worker’s @@ -115,14 +120,13 @@ changes to `ThreadPool` to explicitly drop `sender`. We use the same `Option` and `take` technique as we did with the thread to be able to move `sender` out of `ThreadPool`: -Filename: src/lib.rs + ```rust,noplayground,not_desired_behavior {{#rustdoc_include ../listings/ch21-web-server/listing-21-23/src/lib.rs:here}} ``` -Listing 21-23: Explicitly drop `sender` before joining -the worker threads + Dropping `sender` closes the channel, which indicates no more messages will be sent. When that happens, all the calls to `recv` that the workers do in the @@ -130,26 +134,24 @@ infinite loop will return an error. In Listing 21-24, we change the `Worker` loop to gracefully exit the loop in that case, which means the threads will finish when the `ThreadPool` `drop` implementation calls `join` on them. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch21-web-server/listing-21-24/src/lib.rs:here}} ``` -Listing 21-24: Explicitly break out of the loop when -`recv` returns an error + To see this code in action, let’s modify `main` to accept only two requests before gracefully shutting down the server, as shown in Listing 21-25. -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch21-web-server/listing-21-25/src/main.rs:here}} ``` -Listing 21-25: Shut down the server after serving two -requests by exiting the loop + You wouldn’t want a real-world web server to shut down after serving only two requests. This code just demonstrates that the graceful shutdown and cleanup is @@ -213,18 +215,22 @@ shutdown of the server, which cleans up all the threads in the pool. Here’s the full code for reference: -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch21-web-server/no-listing-07-final-code/src/main.rs}} ``` -Filename: src/lib.rs + + + ```rust,noplayground {{#rustdoc_include ../listings/ch21-web-server/no-listing-07-final-code/src/lib.rs}} ``` + + We could do more here! If you want to continue enhancing this project, here are some ideas: