diff --git a/second-edition/src/ch13-02-iterators.md b/second-edition/src/ch13-02-iterators.md index 3b4e86373..38df37df4 100644 --- a/second-edition/src/ch13-02-iterators.md +++ b/second-edition/src/ch13-02-iterators.md @@ -49,7 +49,7 @@ for val in v1_iter { } ``` -Listing 13-13: Making use of an iterator in a `for` +Listing 13-14: Making use of an iterator in a `for` loop In languages that don’t have iterators provided by their standard libraries, we @@ -88,7 +88,7 @@ that’s returned from the iterator. The `next` method is the only method that the `Iterator` trait requires implementers of the trait to define. `next` returns one item of the iterator at a time wrapped in `Some`, and when iteration is over, it returns `None`. -We can call the `next` method on iterators directly if we’d like; Listing 13-14 +We can call the `next` method on iterators directly if we’d like; Listing 13-15 has a test that demonstrates the values we’d get on repeated calls to `next` on the iterator created from the vector: @@ -108,7 +108,7 @@ fn iterator_demonstration() { } ``` -Listing 13-14: Calling the `next` method on an +Listing 13-15: Calling the `next` method on an iterator Note that we needed to make `v1_iter` mutable: calling the `next` method on an @@ -157,7 +157,7 @@ calling them uses up the iterator. An example of a consuming adaptor is the `sum` method. This method takes ownership of the iterator and iterates through the items by repeatedly calling `next`, thus consuming the iterator. As it iterates through each item, it adds each item to a running total and returns -the total when iteration has completed. Listing 13-15 has a test illustrating a +the total when iteration has completed. Listing 13-16 has a test illustrating a use of the `sum` method: Filename: src/lib.rs @@ -175,7 +175,7 @@ fn iterator_sum() { } ``` -Listing 13-15: Calling the `sum` method to get the total +Listing 13-16: 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` since `sum` takes @@ -188,7 +188,7 @@ other iterators. These methods are called *iterator adaptors* and allow us to change iterators into different kind of iterators. We can chain multiple calls to iterator adaptors. Because all iterators are lazy, however, we have to call one of the consuming adaptor methods in order to get results from calls -to iterator adaptors. Listing 13-16 shows an example of calling the iterator +to iterator adaptors. Listing 13-17 shows an example of calling the iterator adaptor method `map`, which takes a closure that `map` will call on each item in order to produce a new iterator in which each item from the vector has been incremented by 1. This code produces a warning, though: @@ -201,7 +201,7 @@ let v1: Vec = vec![1, 2, 3]; v1.iter().map(|x| x + 1); ``` -Listing 13-16: Calling the iterator adapter `map` to +Listing 13-17: Calling the iterator adapter `map` to create a new iterator The warning we get is: @@ -217,14 +217,14 @@ nothing unless consumed = note: #[warn(unused_must_use)] on by default ``` -The code in Listing 13-16 isn’t actually doing anything; the closure we’ve +The code in Listing 13-17 isn’t actually doing anything; the closure we’ve specified never gets called. The warning reminds us why: iterator adaptors are lazy, and we probably meant to consume the iterator here. In order to fix this warning and consume the iterator to get a useful result, we’re going to use the `collect` method, which we saw briefly in Chapter 12. This method consumes the iterator and collects the resulting values into a -data structure. In Listing 13-17, we’re going to collect the results of +data structure. In Listing 13-18, we’re going to collect the results of iterating over the iterator returned from the call to `map` into a vector that will contain each item from the original vector incremented by 1: @@ -238,7 +238,7 @@ let v2: Vec<_> = v1.iter().map(|x| x + 1).collect(); assert_eq!(v2, vec![2, 3, 4]); ``` -Listing 13-17: Calling the `map` method to create a new +Listing 13-18: Calling the `map` method to create a new iterator, then calling the `collect` method to consume the new iterator and create a vector @@ -268,7 +268,7 @@ closures that capture their environment by using the `filter` iterator adapter. The `filter` method on an iterator takes a closure that takes each item from the iterator and returns a boolean. If the closure returns `true`, the value will be included in the iterator produced by `filter`. If the closure returns -`false`, the value won’t be included in the resulting iterator. Listing 13-18 +`false`, the value won’t be included in the resulting iterator. Listing 13-19 demonstrates using `filter` with a closure that captures the `shoe_size` variable from its environment in order to iterate over a collection of `Shoe` struct instances in order to return only shoes that are the specified size: @@ -308,7 +308,7 @@ fn filters_by_size() { } ``` -Listing 13-18: Using the `filter` method with a closure +Listing 13-19: Using the `filter` method with a closure that captures `shoe_size` @@ -353,7 +353,7 @@ to 5. First, we’ll create a struct to hold on to some values, and then we’ll make this struct into an iterator by implementing the `Iterator` trait and use the values in that implementation. -Listing 13-19 has the definition of the `Counter` struct and an associated +Listing 13-20 has the definition of the `Counter` struct and an associated `new` function to create instances of `Counter`: Filename: src/lib.rs @@ -370,7 +370,7 @@ impl Counter { } ``` -Listing 13-19: Defining the `Counter` struct and a `new` +Listing 13-20: Defining the `Counter` struct and a `new` function that creates instances of `Counter` with an initial value of 0 for `count` @@ -394,7 +394,7 @@ does?--> Next, we’re going to implement the `Iterator` trait for our `Counter` type by defining the body of the `next` method to specify what we want to happen when -this iterator is used, as shown in Listing 13-20: +this iterator is used, as shown in Listing 13-21: Filename: src/lib.rs @@ -418,7 +418,7 @@ impl Iterator for Counter { } ``` -Listing 13-20: Implementing the `Iterator` trait on our +Listing 13-21: Implementing the `Iterator` trait on our `Counter` struct @@ -433,10 +433,10 @@ higher, our iterator will return `None`. #### Using Our `Counter` Iterator’s `next` Method -Once we’ve implemented the `Iterator` trait, we have an iterator! Listing 13-21 +Once we’ve implemented the `Iterator` trait, we have an iterator! Listing 13-22 shows a test demonstrating that we can use the iterator functionality our `Counter` struct now has by calling the `next` method on it directly, just like -we did with the iterator created from a vector in Listing 13-14: +we did with the iterator created from a vector in Listing 13-15: Filename: src/lib.rs @@ -472,7 +472,7 @@ fn calling_next_directly() { } ``` -Listing 13-21: Testing the functionality of the `next` +Listing 13-22: Testing the functionality of the `next` method implementation This test creates a new `Counter` instance in the `counter` variable and then @@ -511,7 +511,7 @@ of `Counter` produces, pair those values with values produced by another `Counter` instance after skipping the first value that instance produces, multiply each pair together, keep only those results that are divisible by three, and add all the resulting values together, we could do so as shown in -the test in Listing 13-22: +the test in Listing 13-23: Filename: src/lib.rs @@ -553,7 +553,7 @@ fn using_other_iterator_trait_methods() { } ``` -Listing 13-22: Using a variety of `Iterator` trait +Listing 13-23: Using a variety of `Iterator` trait methods on our `Counter` iterator Note that `zip` produces only four pairs; the theoretical fifth pair `(5, diff --git a/second-edition/src/ch13-03-improving-our-io-project.md b/second-edition/src/ch13-03-improving-our-io-project.md index 59b195a4c..9ba056c47 100644 --- a/second-edition/src/ch13-03-improving-our-io-project.md +++ b/second-edition/src/ch13-03-improving-our-io-project.md @@ -10,7 +10,7 @@ function and the `search` function. In Listing 12-13, we had code that took a slice of `String` values and created an instance of the `Config` struct by checking for the right number of arguments, indexing into the slice, and cloning the values so that the `Config` -struct could own those values. We’ve reproduced the code here in Listing 13-23: +struct could own those values. We’ve reproduced the code here in Listing 13-24: Filename: src/main.rs @@ -31,7 +31,7 @@ impl Config { } ``` -Listing 13-23: Reproduction of the `Config::new` function +Listing 13-24: Reproduction of the `Config::new` function from Listing 12-13 @@ -139,7 +139,7 @@ impl Config { // ...snip... ``` -Listing 13-25: Updating the signature of `Config::new` to +Listing 13-26: Updating the signature of `Config::new` to expect an iterator The standard library documentation for the `env::args` function shows that the @@ -151,7 +151,7 @@ type `std::env::Args` instead of `&[String]`. Next, we’ll fix the body of `Config::new`. The standard library documentation also mentions that `std::env::Args` implements the `Iterator` trait, so we know -we can call the `next` method on it! Listing 13-26 has the new code: +we can call the `next` method on it! Listing 13-27 has the new code: Filename: src/lib.rs @@ -182,7 +182,7 @@ impl Config { } ``` -Listing 13-26: Changing the body of `Config::new` to use +Listing 13-27: Changing the body of `Config::new` to use iterator methods @@ -209,7 +209,7 @@ probably just distracting to most people /Carol --> The other place in our I/O project we could take advantage of iterators is in the `search` function, as implemented in Listing 12-19 and reproduced here in -Listing 13-27: +Listing 13-28: Filename: src/lib.rs @@ -227,7 +227,7 @@ fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { } ``` -Listing 13-27: The implementation of the `search` +Listing 13-28: The implementation of the `search` function from Listing 12-19 We can write this code in a much shorter way by using iterator adaptor methods @@ -236,7 +236,7 @@ vector. The functional programming style prefers to minimize the amount of mutable state to make code clearer. Removing the mutable state might make it easier for us to make a future enhancement to make searching happen in parallel, since we wouldn’t have to manage concurrent access to the `results` -vector. Listing 13-28 shows this change: +vector. Listing 13-29 shows this change: @@ -251,12 +251,12 @@ fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { } ``` -Listing 13-28: Using iterator adaptor methods in the +Listing 13-29: 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`. Similarly to the `filter` example in -Listing 13-18, we can use the `filter` adaptor to keep only the lines that +Listing 13-19, we can use the `filter` adaptor to keep only the lines that `line.contains(query)` returns true for. We then collect the matching lines up into another vector with `collect`. Much simpler! @@ -266,8 +266,8 @@ details I'm afraid --> The next logical question is which style you should choose in your own code: -the original implementation in Listing 13-27, or the version using iterators in -Listing 13-28. Most Rust programmers prefer to use the iterator style. It’s a +the original implementation in Listing 13-28, or the version using iterators in +Listing 13-29. Most Rust programmers prefer to use the iterator style. It’s a bit tougher to get the hang of at first, but once you get a feel for the various iterator adaptors and what they do, iterators can be easier to understand. Instead of fiddling with the various bits of looping and building