From 11e2e3ff3724b24b345cd1df5bc6a84fe345df19 Mon Sep 17 00:00:00 2001 From: bryanzierk Date: Wed, 12 Jun 2024 13:14:18 -0600 Subject: [PATCH 1/3] Convert chapters 12-15 --- ...h12-01-accepting-command-line-arguments.md | 10 ++-- src/ch12-02-reading-a-file.md | 10 ++-- ...improving-error-handling-and-modularity.md | 50 ++++++++----------- ...2-04-testing-the-librarys-functionality.md | 25 ++++------ ...2-05-working-with-environment-variables.md | 20 +++----- ...-06-writing-to-stderr-instead-of-stdout.md | 5 +- src/ch13-01-closures.md | 44 +++++++--------- src/ch13-02-iterators.md | 34 ++++++------- src/ch13-03-improving-our-io-project.md | 30 +++++------ src/ch14-02-publishing-to-crates-io.md | 30 +++++------ src/ch14-03-cargo-workspaces.md | 5 +- src/ch15-01-box.md | 25 ++++------ src/ch15-02-deref.md | 38 ++++++-------- src/ch15-03-drop.md | 15 +++--- src/ch15-04-rc.md | 14 +++--- src/ch15-05-interior-mutability.md | 25 ++++------ src/ch15-06-reference-cycles.md | 25 ++++------ 17 files changed, 168 insertions(+), 237 deletions(-) diff --git a/src/ch12-01-accepting-command-line-arguments.md b/src/ch12-01-accepting-command-line-arguments.md index bb69366633..9dc28209b7 100644 --- a/src/ch12-01-accepting-command-line-arguments.md +++ b/src/ch12-01-accepting-command-line-arguments.md @@ -39,14 +39,13 @@ the iterator produces. The code in Listing 12-1 allows your `minigrep` program to read any command line arguments passed to it and then collect the values into a vector. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-01/src/main.rs}} ``` -Listing 12-1: Collecting the command line arguments into -a vector and printing them + First, we bring the `std::env` module into scope with a `use` statement so we can use its `args` function. Notice that the `std::env::args` function is @@ -101,14 +100,13 @@ arguments. Now we need to save the values of the two arguments in variables so we can use the values throughout the rest of the program. We do that in Listing 12-2. -Filename: src/main.rs + ```rust,should_panic,noplayground {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-02/src/main.rs}} ``` -Listing 12-2: Creating variables to hold the query -argument and file path argument + As we saw when we printed the vector, the program’s name takes up the first value in the vector at `args[0]`, so we’re starting arguments at index `1`. The diff --git a/src/ch12-02-reading-a-file.md b/src/ch12-02-reading-a-file.md index d8340a2a07..910850b06b 100644 --- a/src/ch12-02-reading-a-file.md +++ b/src/ch12-02-reading-a-file.md @@ -7,26 +7,24 @@ has an Emily Dickinson poem that will work well! Create a file called *poem.txt* at the root level of your project, and enter the poem “I’m Nobody! Who are you?” -Filename: poem.txt + ```text {{#include ../listings/ch12-an-io-project/listing-12-03/poem.txt}} ``` -Listing 12-3: A poem by Emily Dickinson makes a good test -case + With the text in place, edit *src/main.rs* and add code to read the file, as shown in Listing 12-4. -Filename: src/main.rs + ```rust,should_panic,noplayground {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-04/src/main.rs:here}} ``` -Listing 12-4: Reading the contents of the file specified -by the second argument + First, we bring in a relevant part of the standard library with a `use` statement: we need `std::fs` to handle files. diff --git a/src/ch12-03-improving-error-handling-and-modularity.md b/src/ch12-03-improving-error-handling-and-modularity.md index 1b67d63d6d..a082737d9a 100644 --- a/src/ch12-03-improving-error-handling-and-modularity.md +++ b/src/ch12-03-improving-error-handling-and-modularity.md @@ -70,14 +70,13 @@ We’ll extract the functionality for parsing arguments into a function that *src/lib.rs*. Listing 12-5 shows the new start of `main` that calls a new function `parse_config`, which we’ll define in *src/main.rs* for the moment. -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-05/src/main.rs:here}} ``` -Listing 12-5: Extracting a `parse_config` function from -`main` + We’re still collecting the command line arguments into a vector, but instead of assigning the argument value at index 1 to the variable `query` and the @@ -112,14 +111,13 @@ other and what their purpose is. Listing 12-6 shows the improvements to the `parse_config` function. -Filename: src/main.rs + ```rust,should_panic,noplayground {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-06/src/main.rs:here}} ``` -Listing 12-6: Refactoring `parse_config` to return an -instance of a `Config` struct + We’ve added a struct named `Config` defined to have fields named `query` and `file_path`. The signature of `parse_config` now indicates that it returns a @@ -179,14 +177,13 @@ changing `parse_config` into a `new` function associated with `Config`, we’ll be able to create instances of `Config` by calling `Config::new`. Listing 12-7 shows the changes we need to make. -Filename: src/main.rs + ```rust,should_panic,noplayground {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-07/src/main.rs:here}} ``` -Listing 12-7: Changing `parse_config` into -`Config::new` + We’ve updated `main` where we were calling `parse_config` to instead call `Config::new`. We’ve changed the name of `parse_config` to `new` and moved it @@ -214,14 +211,13 @@ In Listing 12-8, we add a check in the `new` function that will verify that the slice is long enough before accessing index 1 and 2. If the slice isn’t long enough, the program panics and displays a better error message. -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-08/src/main.rs:here}} ``` -Listing 12-8: Adding a check for the number of -arguments + This code is similar to [the `Guess::new` function we wrote in Listing 9-13][ch9-custom-types], where we called `panic!` when the @@ -265,14 +261,13 @@ function we’re now calling `Config::build` and the body of the function needed to return a `Result`. Note that this won’t compile until we update `main` as well, which we’ll do in the next listing. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-09/src/main.rs:here}} ``` -Listing 12-9: Returning a `Result` from -`Config::build` + Our `build` function returns a `Result` with a `Config` instance in the success case and a `&'static str` in the error case. Our error values will always be @@ -299,14 +294,13 @@ tool with a nonzero error code away from `panic!` and instead implement it by hand. A nonzero exit status is a convention to signal to the process that called our program that the program exited with an error state. -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-10/src/main.rs:here}} ``` -Listing 12-10: Exiting with an error code if building a -`Config` fails + In this listing, we’ve used a method we haven’t covered in detail yet: `unwrap_or_else`, which is defined on `Result` by the standard library. @@ -350,14 +344,15 @@ Listing 12-11 shows the extracted `run` function. For now, we’re just making the small, incremental improvement of extracting the function. We’re still defining the function in *src/main.rs*. ++ Filename: src/main.rs ```rust,ignore {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-11/src/main.rs:here}} ``` -Listing 12-11: Extracting a `run` function containing the -rest of the program logic + The `run` function now contains all the remaining logic from `main`, starting from reading the file. The `run` function takes the `Config` instance as an @@ -373,14 +368,13 @@ us further consolidate the logic around handling errors into `main` in a user-friendly way. Listing 12-12 shows the changes we need to make to the signature and body of `run`. -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-12/src/main.rs:here}} ``` -Listing 12-12: Changing the `run` function to return -`Result` + We’ve made three significant changes here. First, we changed the return type of the `run` function to `Result<(), Box>`. This function previously @@ -458,14 +452,13 @@ The contents of *src/lib.rs* should have the signatures shown in Listing 12-13 (we’ve omitted the bodies of the functions for brevity). Note that this won’t compile until we modify *src/main.rs* in Listing 12-14. -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-13/src/lib.rs:here}} ``` -Listing 12-13: Moving `Config` and `run` into -*src/lib.rs* + We’ve made liberal use of the `pub` keyword: on `Config`, on its fields and its `build` method, and on the `run` function. We now have a library crate that has @@ -474,14 +467,13 @@ a public API we can test! Now we need to bring the code we moved to *src/lib.rs* into the scope of the binary crate in *src/main.rs*, as shown in Listing 12-14. -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-14/src/main.rs:here}} ``` -Listing 12-14: Using the `minigrep` library crate in -*src/main.rs* + We add a `use minigrep::Config` line to bring the `Config` type from the library crate into the binary crate’s scope, and we prefix the `run` function diff --git a/src/ch12-04-testing-the-librarys-functionality.md b/src/ch12-04-testing-the-librarys-functionality.md index 129f835aa1..c4a435bc08 100644 --- a/src/ch12-04-testing-the-librarys-functionality.md +++ b/src/ch12-04-testing-the-librarys-functionality.md @@ -35,14 +35,13 @@ behavior we want the `search` function to have: it will take a query and the text to search, and it will return only the lines from the text that contain the query. Listing 12-15 shows this test, which won’t compile yet. -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-15/src/lib.rs:here}} ``` -Listing 12-15: Creating a failing test for the `search` -function we wish we had + This test searches for the string `"duct"`. The text we’re searching is three lines, only one of which contains `"duct"` (Note that the backslash after the @@ -58,14 +57,13 @@ vector, as shown in Listing 12-16. Then the test should compile and fail because an empty vector doesn’t match a vector containing the line `"safe, fast, productive."` -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-16/src/lib.rs:here}} ``` -Listing 12-16: Defining just enough of the `search` -function so our test will compile + Notice that we need to define an explicit lifetime `'a` in the signature of `search` and use that lifetime with the `contents` argument and the return @@ -128,14 +126,13 @@ Rust has a helpful method to handle line-by-line iteration of strings, conveniently named `lines`, that works as shown in Listing 12-17. Note this won’t compile yet. -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-17/src/lib.rs:here}} ``` -Listing 12-17: Iterating through each line in `contents` - + The `lines` method returns an iterator. We’ll talk about iterators in depth in [Chapter 13][ch13-iterators], but recall that you saw this way @@ -149,14 +146,13 @@ Fortunately, strings have a helpful method named `contains` that does this for us! Add a call to the `contains` method in the `search` function, as shown in Listing 12-18. Note this still won’t compile yet. -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-18/src/lib.rs:here}} ``` -Listing 12-18: Adding functionality to see whether the -line contains the string in `query` + At the moment, we’re building up functionality. To get it to compile, we need to return a value from the body as we indicated we would in the function @@ -169,14 +165,13 @@ to return. For that, we can make a mutable vector before the `for` loop and call the `push` method to store a `line` in the vector. After the `for` loop, we return the vector, as shown in Listing 12-19. -Filename: src/lib.rs + ```rust,ignore {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-19/src/lib.rs:here}} ``` -Listing 12-19: Storing the lines that match so we can -return them + Now the `search` function should return only the lines that contain `query`, and our test should pass. Let’s run the test: diff --git a/src/ch12-05-working-with-environment-variables.md b/src/ch12-05-working-with-environment-variables.md index 263c80cd06..f050b5b479 100644 --- a/src/ch12-05-working-with-environment-variables.md +++ b/src/ch12-05-working-with-environment-variables.md @@ -16,14 +16,13 @@ the new `search_case_insensitive` function and rename our old test from `one_result` to `case_sensitive` to clarify the differences between the two tests, as shown in Listing 12-20. -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-20/src/lib.rs:here}} ``` -Listing 12-20: Adding a new failing test for the -case-insensitive function we’re about to add + Note that we’ve edited the old test’s `contents` too. We’ve added a new line with the text `"Duct tape."` using a capital D that shouldn’t match the query @@ -48,14 +47,13 @@ the same as the `search` function. The only difference is that we’ll lowercase the `query` and each `line` so whatever the case of the input arguments, they’ll be the same case when we check whether the line contains the query. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-21/src/lib.rs:here}} ``` -Listing 12-21: Defining the `search_case_insensitive` -function to lowercase the query and the line before comparing them + First, we lowercase the `query` string and store it in a shadowed variable with the same name. Calling `to_lowercase` on the query is necessary so no @@ -101,14 +99,13 @@ function to check the `ignore_case` field’s value and use that to decide whether to call the `search` function or the `search_case_insensitive` function, as shown in Listing 12-22. This still won’t compile yet. -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-22/src/lib.rs:there}} ``` -Listing 12-22: Calling either `search` or -`search_case_insensitive` based on the value in `config.ignore_case` + Finally, we need to check for the environment variable. The functions for working with environment variables are in the `env` module in the standard @@ -117,14 +114,13 @@ we’ll use the `var` function from the `env` module to check if any value has been set for an environment variable named `IGNORE_CASE`, as shown in Listing 12-23. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-23/src/lib.rs:here}} ``` -Listing 12-23: Checking for any value in an environment -variable named `IGNORE_CASE` + Here, we create a new variable `ignore_case`. To set its value, we call the `env::var` function and pass it the name of the `IGNORE_CASE` environment diff --git a/src/ch12-06-writing-to-stderr-instead-of-stdout.md b/src/ch12-06-writing-to-stderr-instead-of-stdout.md index d017fa3245..99e50e6f00 100644 --- a/src/ch12-06-writing-to-stderr-instead-of-stdout.md +++ b/src/ch12-06-writing-to-stderr-instead-of-stdout.md @@ -54,14 +54,13 @@ the `eprintln!` macro that prints to the standard error stream, so let’s chang the two places we were calling `println!` to print errors to use `eprintln!` instead. -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-24/src/main.rs:here}} ``` -Listing 12-24: Writing error messages to standard error -instead of standard output using `eprintln!` + Let’s now run the program again in the same way, without any arguments and redirecting standard output with `>`: diff --git a/src/ch13-01-closures.md b/src/ch13-01-closures.md index a1e1cec80e..1983fbdacf 100644 --- a/src/ch13-01-closures.md +++ b/src/ch13-01-closures.md @@ -35,13 +35,13 @@ The method `giveaway` defined on `Inventory` gets the optional shirt color preference of the free shirt winner, and returns the shirt color the person will get. This setup is shown in Listing 13-1: -Filename: src/main.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch13-functional-features/listing-13-01/src/main.rs}} ``` -Listing 13-1: Shirt company giveaway situation + The `store` defined in `main` has two blue shirts and one red shirt remaining to distribute for this limited-edition promotion. We call the `giveaway` method @@ -105,14 +105,13 @@ shown in Listing 13-2. In this example, we’re defining a closure and storing i in a variable rather than defining the closure in the spot we pass it as an argument as we did in Listing 13-1. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch13-functional-features/listing-13-02/src/main.rs:here}} ``` -Listing 13-2: Adding optional type annotations of the -parameter and return value types in the closure + With type annotations added, the syntax of closures looks more similar to the syntax of functions. Here we define a function that adds 1 to its parameter and @@ -147,14 +146,13 @@ Because there are no type annotations, we can call the closure with any type, which we’ve done here with `String` the first time. If we then try to call `example_closure` with an integer, we’ll get an error. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch13-functional-features/listing-13-03/src/main.rs:here}} ``` -Listing 13-3: Attempting to call a closure whose types -are inferred with two different types + The compiler gives us this error: @@ -179,14 +177,13 @@ In Listing 13-4, we define a closure that captures an immutable reference to the vector named `list` because it only needs an immutable reference to print the value: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch13-functional-features/listing-13-04/src/main.rs}} ``` -Listing 13-4: Defining and calling a closure that -captures an immutable reference + This example also illustrates that a variable can bind to a closure definition, and we can later call the closure by using the variable name and parentheses as @@ -204,14 +201,13 @@ is called. This code compiles, runs, and prints: Next, in Listing 13-5, we change the closure body so that it adds an element to the `list` vector. The closure now captures a mutable reference: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch13-functional-features/listing-13-05/src/main.rs}} ``` -Listing 13-5: Defining and calling a closure that -captures a mutable reference + This code compiles, runs, and prints: @@ -238,14 +234,13 @@ concurrency, but for now, let’s briefly explore spawning a new thread using a closure that needs the `move` keyword. Listing 13-6 shows Listing 13-4 modified to print the vector in a new thread rather than in the main thread: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch13-functional-features/listing-13-06/src/main.rs}} ``` -Listing 13-6: Using `move` to force the closure for the -thread to take ownership of `list` + We spawn a new thread, giving the thread a closure to run as an argument. The closure body prints out the list. In Listing 13-4, the closure only captured @@ -348,14 +343,13 @@ when you want to sort a slice by a particular attribute of each item. In Listing 13-7, we have a list of `Rectangle` instances and we use `sort_by_key` to order them by their `width` attribute from low to high: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch13-functional-features/listing-13-07/src/main.rs}} ``` -Listing 13-7: Using `sort_by_key` to order rectangles by -width + This code prints: @@ -372,14 +366,13 @@ In contrast, Listing 13-8 shows an example of a closure that implements just the `FnOnce` trait, because it moves a value out of the environment. The compiler won’t let us use this closure with `sort_by_key`: -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch13-functional-features/listing-13-08/src/main.rs}} ``` -Listing 13-8: Attempting to use an `FnOnce` closure with -`sort_by_key` + This is a contrived, convoluted way (that doesn’t work) to try and count the number of times `sort_by_key` calls the closure when sorting `list`. This code @@ -406,14 +399,13 @@ in Listing 13-9 works with `sort_by_key` because it is only capturing a mutable reference to the `num_sort_operations` counter and can therefore be called more than once: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch13-functional-features/listing-13-09/src/main.rs}} ``` -Listing 13-9: Using an `FnMut` closure with `sort_by_key` -is allowed + The `Fn` traits are important when defining or using functions or types that make use of closures. In the next section, we’ll discuss iterators. Many diff --git a/src/ch13-02-iterators.md b/src/ch13-02-iterators.md index 030ebf48eb..c99fcd6998 100644 --- a/src/ch13-02-iterators.md +++ b/src/ch13-02-iterators.md @@ -11,11 +11,13 @@ Listing 13-10 creates an iterator over the items in the vector `v1` by calling the `iter` method defined on `Vec`. This code by itself doesn’t do anything useful. ++ ```rust {{#rustdoc_include ../listings/ch13-functional-features/listing-13-10/src/main.rs:here}} ``` -Listing 13-10: Creating an iterator + The iterator is stored in the `v1_iter` variable. Once we’ve created an iterator, we can use it in a variety of ways. In Listing 3-5 in Chapter 3, we @@ -28,11 +30,13 @@ the use of the iterator in the `for` loop. When the `for` loop is called using the iterator in `v1_iter`, each element in the iterator is used in one iteration of the loop, which prints out each value. ++ ```rust {{#rustdoc_include ../listings/ch13-functional-features/listing-13-11/src/main.rs:here}} ``` -Listing 13-11: Using an iterator in a `for` loop + In languages that don’t have iterators provided by their standard libraries, you would likely write this same functionality by starting a variable at index @@ -76,14 +80,13 @@ We can call the `next` method on iterators directly; Listing 13-12 demonstrates what values are returned from repeated calls to `next` on the iterator created from the vector. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch13-functional-features/listing-13-12/src/lib.rs:here}} ``` -Listing 13-12: Calling the `next` method on an -iterator + Note that we needed to make `v1_iter` mutable: calling the `next` method on an iterator changes internal state that the iterator uses to keep track of where @@ -115,14 +118,13 @@ consuming the iterator. As it iterates through, it adds each item to a running total and returns the total when iteration is complete. Listing 13-13 has a test illustrating a use of the `sum` method: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch13-functional-features/listing-13-13/src/lib.rs:here}} ``` -Listing 13-13: Calling the `sum` method to get the total -of all items in the iterator + We aren’t allowed to use `v1_iter` after the call to `sum` because `sum` takes ownership of the iterator we call it on. @@ -139,14 +141,13 @@ The `map` method returns a new iterator that produces the modified items. The closure here creates a new iterator in which each item from the vector will be incremented by 1: -Filename: src/main.rs + ```rust,not_desired_behavior {{#rustdoc_include ../listings/ch13-functional-features/listing-13-14/src/main.rs:here}} ``` -Listing 13-14: Calling the iterator adaptor `map` to -create a new iterator + However, this code produces a warning: @@ -167,15 +168,13 @@ In Listing 13-15, we collect the results of iterating over the iterator that’s returned from the call to `map` into a vector. This vector will end up containing each item from the original vector incremented by 1. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch13-functional-features/listing-13-15/src/main.rs:here}} ``` -Listing 13-15: Calling the `map` method to create a new -iterator and then calling the `collect` method to consume the new iterator and -create a vector + Because `map` takes a closure, we can specify any operation we want to perform on each item. This is a great example of how closures let you customize some @@ -201,14 +200,13 @@ In Listing 13-16, we use `filter` with a closure that captures the `shoe_size` variable from its environment to iterate over a collection of `Shoe` struct instances. It will return only shoes that are the specified size. -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch13-functional-features/listing-13-16/src/lib.rs}} ``` -Listing 13-16: Using the `filter` method with a closure -that captures `shoe_size` + The `shoes_in_size` function takes ownership of a vector of shoes and a shoe size as parameters. It returns a vector containing only shoes of the specified diff --git a/src/ch13-03-improving-our-io-project.md b/src/ch13-03-improving-our-io-project.md index e4deec5627..4c1a508458 100644 --- a/src/ch13-03-improving-our-io-project.md +++ b/src/ch13-03-improving-our-io-project.md @@ -13,14 +13,13 @@ values, allowing the `Config` struct to own those values. In Listing 13-17, we’ve reproduced the implementation of the `Config::build` function as it was in Listing 12-23: -Filename: src/lib.rs + ```rust,ignore {{#rustdoc_include ../listings/ch13-functional-features/listing-12-23-reproduced/src/lib.rs:ch13}} ``` -Listing 13-17: Reproduction of the `Config::build` -function from Listing 12-23 + At the time, we said not to worry about the inefficient `clone` calls because we would remove them in the future. Well, that time is now! @@ -54,14 +53,13 @@ We’ll first change the start of the `main` function that we had in Listing 12-24 to the code in Listing 13-18, which this time uses an iterator. This won’t compile until we update `Config::build` as well. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch13-functional-features/listing-13-18/src/main.rs:here}} ``` -Listing 13-18: Passing the return value of `env::args` to -`Config::build` + The `env::args` function returns an iterator! Rather than collecting the iterator values into a vector and then passing a slice to `Config::build`, now @@ -73,14 +71,13 @@ project’s *src/lib.rs* file, let’s change the signature of `Config::build` t look like Listing 13-19. This still won’t compile because we need to update the function body. -Filename: src/lib.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch13-functional-features/listing-13-19/src/lib.rs:here}} ``` -Listing 13-19: Updating the signature of `Config::build` -to expect an iterator + The standard library documentation for the `env::args` function shows that the type of the iterator it returns is `std::env::Args`, and that type implements @@ -103,14 +100,13 @@ Next, we’ll fix the body of `Config::build`. Because `args` implements the `Iterator` trait, we know we can call the `next` method on it! Listing 13-20 updates the code from Listing 12-23 to use the `next` method: -Filename: src/lib.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch13-functional-features/listing-13-20/src/lib.rs:here}} ``` -Listing 13-20: Changing the body of `Config::build` to use -iterator methods + Remember that the first value in the return value of `env::args` is the name of the program. We want to ignore that and get to the next value, so first we call @@ -125,14 +121,13 @@ the same thing for the `file_path` value. We can also take advantage of iterators in the `search` function in our I/O project, which is reproduced here in Listing 13-21 as it was in Listing 12-19: -Filename: src/lib.rs + ```rust,ignore {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-19/src/lib.rs:ch13}} ``` -Listing 13-21: The implementation of the `search` -function from Listing 12-19 + We can write this code in a more concise way using iterator adaptor methods. Doing so also lets us avoid having a mutable intermediate `results` vector. The @@ -141,14 +136,13 @@ make code clearer. Removing the mutable state might enable a future enhancement to make searching happen in parallel, because we wouldn’t have to manage concurrent access to the `results` vector. Listing 13-22 shows this change: -Filename: src/lib.rs + ```rust,ignore {{#rustdoc_include ../listings/ch13-functional-features/listing-13-22/src/lib.rs:here}} ``` -Listing 13-22: Using iterator adaptor methods in the -implementation of the `search` function + Recall that the purpose of the `search` function is to return all lines in `contents` that contain the `query`. Similar to the `filter` example in Listing diff --git a/src/ch14-02-publishing-to-crates-io.md b/src/ch14-02-publishing-to-crates-io.md index d4d33babc4..b4cfb22d6c 100644 --- a/src/ch14-02-publishing-to-crates-io.md +++ b/src/ch14-02-publishing-to-crates-io.md @@ -26,14 +26,13 @@ Markdown notation for formatting the text. Place documentation comments just before the item they’re documenting. Listing 14-1 shows documentation comments for an `add_one` function in a crate named `my_crate`. -Filename: src/lib.rs + ```rust,ignore {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-01/src/lib.rs}} ``` -Listing 14-1: A documentation comment for a -function + Here, we give a description of what the `add_one` function does, start a section with the heading `Examples`, and then provide code that demonstrates @@ -115,14 +114,13 @@ crate that contains the `add_one` function, we add documentation comments that start with `//!` to the beginning of the *src/lib.rs* file, as shown in Listing 14-2: -Filename: src/lib.rs + ```rust,ignore {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-02/src/lib.rs:here}} ``` -Listing 14-2: Documentation for the `my_crate` crate as a -whole + Notice there isn’t any code after the last line that begins with `//!`. Because we started the comments with `//!` instead of `///`, we’re documenting the item @@ -172,14 +170,13 @@ Within this library are two modules: a `kinds` module containing two enums named `PrimaryColor` and `SecondaryColor` and a `utils` module containing a function named `mix`, as shown in Listing 14-3: -Filename: src/lib.rs + ```rust,noplayground,test_harness {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-03/src/lib.rs:here}} ``` -Listing 14-3: An `art` library with items organized into -`kinds` and `utils` modules + Figure 14-3 shows what the front page of the documentation for this crate generated by `cargo doc` would look like: @@ -198,14 +195,13 @@ bring the items from `art` into scope, specifying the module structure that’s currently defined. Listing 14-4 shows an example of a crate that uses the `PrimaryColor` and `mix` items from the `art` crate: -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-04/src/main.rs}} ``` -Listing 14-4: A crate using the `art` crate’s items with -its internal structure exported + The author of the code in Listing 14-4, which uses the `art` crate, had to figure out that `PrimaryColor` is in the `kinds` module and `mix` is in the @@ -220,14 +216,13 @@ To remove the internal organization from the public API, we can modify the `art` crate code in Listing 14-3 to add `pub use` statements to re-export the items at the top level, as shown in Listing 14-5: -Filename: src/lib.rs + ```rust,ignore {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-05/src/lib.rs:here}} ``` -Listing 14-5: Adding `pub use` statements to re-export -items + The API documentation that `cargo doc` generates for this crate will now list and link re-exports on the front page, as shown in Figure 14-4, making the @@ -242,14 +237,13 @@ The `art` crate users can still see and use the internal structure from Listing 14-3 as demonstrated in Listing 14-4, or they can use the more convenient structure in Listing 14-5, as shown in Listing 14-6: -Filename: src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-06/src/main.rs:here}} ``` -Listing 14-6: A program using the re-exported items from -the `art` crate + In cases where there are many nested modules, re-exporting the types at the top level with `pub use` can make a significant difference in the experience of diff --git a/src/ch14-03-cargo-workspaces.md b/src/ch14-03-cargo-workspaces.md index cbece82335..afc9c65a7c 100644 --- a/src/ch14-03-cargo-workspaces.md +++ b/src/ch14-03-cargo-workspaces.md @@ -142,14 +142,13 @@ Next, let’s use the `add_one` function (from the `add_one` crate) in the top to bring the new `add_one` library crate into scope. Then change the `main` function to call the `add_one` function, as in Listing 14-7. -Filename: adder/src/main.rs + ```rust,ignore {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-07/add/adder/src/main.rs}} ``` -Listing 14-7: Using the `add_one` library crate from the - `adder` crate + Let’s build the workspace by running `cargo build` in the top-level *add* directory! diff --git a/src/ch15-01-box.md b/src/ch15-01-box.md index 53e829a4c3..ae31195682 100644 --- a/src/ch15-01-box.md +++ b/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/src/ch15-02-deref.md b/src/ch15-02-deref.md index 56db7c0a02..d8b60f187b 100644 --- a/src/ch15-02-deref.md +++ b/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/src/ch15-03-drop.md b/src/ch15-03-drop.md index 05ab86873b..8c402f408f 100644 --- a/src/ch15-03-drop.md +++ b/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/src/ch15-04-rc.md b/src/ch15-04-rc.md index 87a42eb1a5..c5bf9a4897 100644 --- a/src/ch15-04-rc.md +++ b/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/src/ch15-05-interior-mutability.md b/src/ch15-05-interior-mutability.md index 7b5e825d7e..c51302b31c 100644 --- a/src/ch15-05-interior-mutability.md +++ b/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/src/ch15-06-reference-cycles.md b/src/ch15-06-reference-cycles.md index beb2bc2169..2ea12edb6f 100644 --- a/src/ch15-06-reference-cycles.md +++ b/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 From 3216c0f57ba4722835785dd4031ded4298a798ee Mon Sep 17 00:00:00 2001 From: bryanzierk Date: Wed, 12 Jun 2024 13:25:53 -0600 Subject: [PATCH 2/3] Remove extraneous span --- src/ch12-03-improving-error-handling-and-modularity.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ch12-03-improving-error-handling-and-modularity.md b/src/ch12-03-improving-error-handling-and-modularity.md index a082737d9a..0de3ec2c22 100644 --- a/src/ch12-03-improving-error-handling-and-modularity.md +++ b/src/ch12-03-improving-error-handling-and-modularity.md @@ -346,8 +346,6 @@ defining the function in *src/main.rs*. -Filename: src/main.rs - ```rust,ignore {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-11/src/main.rs:here}} ``` From c7462f3a15959108a8b69300916a7f5ad68647ed Mon Sep 17 00:00:00 2001 From: bryanzierk Date: Wed, 12 Jun 2024 13:14:18 -0500 Subject: [PATCH 3/3] Revert chapter 15 --- src/ch15-01-box.md | 25 +++++++++++--------- src/ch15-02-deref.md | 38 +++++++++++++++++------------- src/ch15-03-drop.md | 15 +++++++----- src/ch15-04-rc.md | 14 ++++++----- src/ch15-05-interior-mutability.md | 25 ++++++++++++-------- src/ch15-06-reference-cycles.md | 25 ++++++++++++-------- 6 files changed, 83 insertions(+), 59 deletions(-) diff --git a/src/ch15-01-box.md b/src/ch15-01-box.md index ae31195682..53e829a4c3 100644 --- a/src/ch15-01-box.md +++ b/src/ch15-01-box.md @@ -35,13 +35,14 @@ 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 @@ -105,13 +106,14 @@ 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 @@ -121,13 +123,14 @@ we’ll demonstrate. 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 @@ -137,13 +140,12 @@ 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 @@ -213,13 +215,14 @@ 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/src/ch15-02-deref.md b/src/ch15-02-deref.md index d8b60f187b..56db7c0a02 100644 --- a/src/ch15-02-deref.md +++ b/src/ch15-02-deref.md @@ -29,13 +29,14 @@ 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 @@ -62,13 +63,14 @@ 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 @@ -89,13 +91,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 @@ -107,13 +109,14 @@ 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: @@ -134,13 +137,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 @@ -207,25 +210,27 @@ 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 @@ -239,13 +244,14 @@ 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/src/ch15-03-drop.md b/src/ch15-03-drop.md index 8c402f408f..05ab86873b 100644 --- a/src/ch15-03-drop.md +++ b/src/ch15-03-drop.md @@ -28,13 +28,14 @@ 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 @@ -78,13 +79,14 @@ 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: @@ -112,13 +114,14 @@ 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/src/ch15-04-rc.md b/src/ch15-04-rc.md index c5bf9a4897..87a42eb1a5 100644 --- a/src/ch15-04-rc.md +++ b/src/ch15-04-rc.md @@ -48,13 +48,14 @@ 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: @@ -83,13 +84,14 @@ 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 @@ -116,13 +118,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/src/ch15-05-interior-mutability.md b/src/ch15-05-interior-mutability.md index c51302b31c..7b5e825d7e 100644 --- a/src/ch15-05-interior-mutability.md +++ b/src/ch15-05-interior-mutability.md @@ -129,13 +129,14 @@ 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 @@ -155,13 +156,14 @@ 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 @@ -198,13 +200,14 @@ 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>` @@ -246,13 +249,14 @@ 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 @@ -294,13 +298,14 @@ 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/src/ch15-06-reference-cycles.md b/src/ch15-06-reference-cycles.md index 2ea12edb6f..beb2bc2169 100644 --- a/src/ch15-06-reference-cycles.md +++ b/src/ch15-06-reference-cycles.md @@ -15,13 +15,14 @@ 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 @@ -36,13 +37,14 @@ 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 @@ -161,13 +163,14 @@ 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 @@ -204,13 +207,14 @@ 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, @@ -256,13 +260,14 @@ 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