]> git.proxmox.com Git - rustc.git/blobdiff - src/doc/book/nostarch/chapter13.md
New upstream version 1.63.0+dfsg1
[rustc.git] / src / doc / book / nostarch / chapter13.md
index 54e6544b0d3d5439bb44a4cd74106e2b7d8a352c..99f22e10e00a0ea1532ad036c5f850517a7adf9f 100644 (file)
@@ -22,42 +22,51 @@ More specifically, we’ll cover:
 
 * *Closures*, a function-like construct you can store in a variable
 * *Iterators*, a way of processing a series of elements
-* How to use these two features to improve the I/O project in Chapter 12
-* The performance of these two features (Spoiler alert: they’re faster than you
-  might think!)
+* How to use closures and iterators to improve the I/O project in Chapter 12
+* The performance of closures and iterators (Spoiler alert: they’re faster than
+  you might think!)
 
-Other Rust features, such as pattern matching and enums, which we’ve covered in
-other chapters, are influenced by the functional style as well. Mastering
+We’ve already covered some other Rust features, such as pattern matching and
+enums, that are also influenced by the functional style. Because mastering
 closures and iterators is an important part of writing idiomatic, fast Rust
-code, so we’ll devote this entire chapter to them.
+code, we’ll devote this entire chapter to them.
 
-## Closures: Anonymous Functions that Can Capture Their Environment
+## Closures: Anonymous Functions that Capture Their Environment
 
 Rust’s closures are anonymous functions you can save in a variable or pass as
 arguments to other functions. You can create the closure in one place and then
-call the closure to evaluate it in a different context. Unlike functions,
-closures can capture values from the scope in which they’re defined. We’ll
-demonstrate how these closure features allow for code reuse and behavior
+call the closure elsewhere to evaluate it in a different context. Unlike
+functions, closures can capture values from the scope in which they’re defined.
+We’ll demonstrate how these closure features allow for code reuse and behavior
 customization.
 
 ### Capturing the Environment with Closures
 
-The first aspect of closures we’re going to examine is that closures can
-capture values from the environment they’re defined in for later use. Here’s
-the scenario: A t-shirt company gives away a free shirt to someone on their
-mailing list every so often. People on the mailing list can optionally add
-their favorite color to their profile. If the person chosen to get the free
-shirt has their favorite color in their profile, they get that color shirt. If
-the person hasn’t specified a favorite color, they get the color that the
-company currently has the most of.
+We’ll first examine how we can use closures to capture values from the
+environment they’re defined in for later use. Here’s the scenario: Every so
+often, our t-shirt company gives away an exclusive, limited-edition shirt to
+someone on our mailing list as a promotion. People on the mailing list can
+optionally add their favorite color to their profile. If the person chosen for
+a free shirt has their favorite color set, they get that color shirt. If the
+person hasn’t specified a favorite color, they get whatever color the company
+currently has the most of.
 
 There are many ways to implement this. For this example, we’re going to use an
-enum called `ShirtColor` that has the variants `Red` and `Blue`. The
-company’s inventory is represented by an `Inventory` struct that has a field
-named `shirts` that contains a `Vec<ShirtColor>` representing the shirts
-currently in stock. The method `shirt_giveaway` defined on `Inventory` gets the
-optional shirt color preference of the person getting the free shirt, and
-returns the shirt color the person will get. This is shown in Listing 13-1:
+enum called `ShirtColor` that has the variants `Red` and `Blue` (limiting the
+number of colors available for simplicity).
+<!-- are we saying the company only offers shirts in red or blue, or are we just
+starting with these two colors? Likely not important for the code, but good to
+clarify for the narrative! /LC -->
+<!-- Only red and blue, I've clarified here that it's for the purposes of
+making this example simpler. In the previous paragraph, I specified that these
+t-shirts are exclusive, limited-edition promotional items, perhaps that'll make
+the details of this toy make enough sense that the readers aren't distracted
+from the closures! /Carol -->
+We represent the company’s inventory with an `Inventory` struct that has a
+field named `shirts` that contains a `Vec<ShirtColor>` representing the shirt
+colors currently in stock. The method `shirt_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
 
@@ -74,7 +83,7 @@ struct Inventory {
 
 impl Inventory {
     fn giveaway(&self, user_preference: Option<ShirtColor>) -> ShirtColor {
-        user_preference.unwrap_or_else(|| self.most_stocked())
+        user_preference.unwrap_or_else(|| self.most_stocked()) [1]
     }
 
     fn most_stocked(&self) -> ShirtColor {
@@ -97,18 +106,18 @@ impl Inventory {
 
 fn main() {
     let store = Inventory {
-        shirts: vec![ShirtColor::Blue, ShirtColor::Red, ShirtColor::Blue],
+        shirts: vec![ShirtColor::Blue, ShirtColor::Red, ShirtColor::Blue], [2]
     };
 
     let user_pref1 = Some(ShirtColor::Red);
-    let giveaway1 = store.giveaway(user_pref1);
+    let giveaway1 = store.giveaway(user_pref1); [3]
     println!(
         "The user with preference {:?} gets {:?}",
         user_pref1, giveaway1
     );
 
     let user_pref2 = None;
-    let giveaway2 = store.giveaway(user_pref2);
+    let giveaway2 = store.giveaway(user_pref2); [4]
     println!(
         "The user with preference {:?} gets {:?}",
         user_pref2, giveaway2
@@ -116,11 +125,50 @@ fn main() {
 }
 ```
 
-Listing 13-1: Shirt company giveaway
-
-The `store` defined in `main` has two blue shirts and one red shirt in stock.
-Then it calls the `giveaway` method for a user with a preference for a red
-shirt and a user without any preference. Running this code prints:
+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 [2]. We call the `giveaway`
+method for a user with a preference for a red shirt [3] and a user without any
+preference [4].
+<!-- Again... I know this is just a toy example, but it seems jarring for a
+tshirt company to only have three shirts in stock. I think it's fine if we add
+a line earlier that says something like "for the sake of simplicity, we'll deal
+with just two shirt colors, and a small volume of stock" /LC -->
+<!-- I've repeated the detail here that this is a limited-edition promotion,
+hope that helps remove the jarringness! /Carol -->
+
+Again, this code could be implemented in many ways, and here, to focus on
+closures, we’ve stuck to concepts you’ve already learned except for the body of
+the `giveaway` method that uses a closure. In the `giveaway` method, we get the
+user preference as a parameter of type `Option<ShirtColor>` and call the
+`unwrap_or_else` method on `user_preference` [1]. The `unwrap_or_else` method on
+`Option<T>` is defined by the standard library. It takes one argument: a
+closure without any arguments that returns a value `T` (the same type stored in
+the `Some` variant of the `Option<T>`, in this case `ShirtColor`). If the
+`Option<T>` is the `Some` variant, `unwrap_or_else` returns the value from
+within the `Some`. If the `Option<T>` is the `None` variant, `unwrap_or_else`
+calls the closure and returns the value returned by the closure.
+
+We specify the closure expression `|| self.most_stocked()` as the argument to
+`unwrap_or_else`. This is a closure that takes no parameters itself (if the
+closure had parameters, they would appear between the two vertical bars). The
+body of the closure calls `self.most_stocked()`. We’re defining the closure
+here, and the implementation of `unwrap_or_else` will evaluate the closure
+later if the result is needed.
+
+<!-- can you show us the code that here counts as they closure? is it, for
+example, this whole section: (&self, user_preference: Option<ShirtColor>) ->
+ShirtColor { user_preference.unwrap_or_else(|| self.most_stocked()) ? And what
+indicates to Rust that it's a closure? Or do we not need to indicate that, Rust
+doesn't care? I'm thinking about the earlier closure definition "You can create
+the closure in one place and then call the closure elsewhere to evaluate it in
+a different context" -- are we using this aspect of the closure here? Can you
+highligt that in the text? /LC -->
+<!-- I've tried to clarify, and moved the clarification before showing the
+result of running the code. Is this better? /Carol -->
+
+Running this code prints:
 
 ```
 $ cargo run
@@ -131,36 +179,26 @@ The user with preference Some(Red) gets Red
 The user with preference None gets Blue
 ```
 
-Again, this code could be implemented in many ways, but this way uses concepts
-you’ve already learned, except for the body of the `giveaway` method that uses
-a closure. The `giveaway` method takes the user preference `Option<ShirtColor>`
-and calls `unwrap_or_else` on it. The `unwrap_or_else` method on
-`Option<T>` is defined by the standard library.
-It takes one argument: a closure without any arguments that returns a value `T`
-(the same type stored in the `Some` variant of the `Option<T>`, in this case, a
-`ShirtColor`). If the `Option<T>` is the `Some` variant, `unwrap_or_else`
-returns the value from within the `Some`. If the `Option<T>` is the `None`
-variant, `unwrap_or_else` calls the closure and returns the value returned by
-the closure.
-
-This is interesting because we’ve passed a closure that calls
+One interesting aspect here is that we’ve passed a closure that calls
 `self.most_stocked()` on the current `Inventory` instance. The standard library
 didn’t need to know anything about the `Inventory` or `ShirtColor` types we
-defined, or the logic we want to use in this scenario. The closure captured an
-immutable reference to the `self` `Inventory` instance and passed it with the
-code we specified to the `unwrap_or_else` method. Functions are not able to
-capture their environment in this way.
+defined, or the logic we want to use in this scenario. The closure captures an
+immutable reference to the `self` `Inventory` instance and passes it with the
+code we specify to the `unwrap_or_else` method. Functions, on the other hand,
+are not able to capture their environment in this way.
 
 ### Closure Type Inference and Annotation
 
 There are more differences between functions and closures. Closures don’t
 usually require you to annotate the types of the parameters or the return value
 like `fn` functions do. Type annotations are required on functions because
-they’re part of an explicit interface exposed to your users. Defining this
+the types are part of an explicit interface exposed to your users. Defining this
+<!-- functions are part of the explicit interface, or type annotations are? /LC -->
+<!-- I've clarified! /Carol -->
 interface rigidly is important for ensuring that everyone agrees on what types
-of values a function uses and returns. But closures aren’t used in an exposed
-interface like this: they’re stored in variables and used without naming them
-and exposing them to users of our library.
+of values a function uses and returns. Closures, on the other hand, aren’t used
+in an exposed interface like this: they’re stored in variables and used without
+naming them and exposing them to users of our library.
 
 Closures are typically short and relevant only within a narrow context rather
 than in any arbitrary scenario. Within these limited contexts, the compiler can
@@ -171,7 +209,9 @@ needs closure type annotations too).
 As with variables, we can add type annotations if we want to increase
 explicitness and clarity at the cost of being more verbose than is strictly
 necessary. Annotating the types for a closure would look like the definition
-shown in Listing 13-2.
+shown in Listing 13-x. In this example, we’re defining a closure and storing it
+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
 
@@ -183,15 +223,24 @@ let expensive_closure = |num: u32| -> u32 {
 };
 ```
 
-Listing 13-2: Adding optional type annotations of the parameter and return
+Listing 13-x: Adding optional type annotations of the parameter and return
 value types in the closure
+<!-- Interestng, so is this another way to define a closure: with the let
+keywork like a variable? Earlier we defined in (I think!) in the function
+definition: fn giveaway(&self,... Is it worth pointing out different ways they
+can be defined, or should that be obvious to the reader? /LC -->
+<!-- I've tried to clarify the paragraph before the listing, does this clear it
+up? This code is storing the closure in a variable rather than as an argument.
+Closure definitions are expressions and are always defined the same way, it's
+just that they can be used in different contexts like any other expression can.
+I think the reader will understand that? /Carol -->
 
 With type annotations added, the syntax of closures looks more similar to the
-syntax of functions. The following is a vertical comparison of the syntax for
-the definition of a function that adds 1 to its parameter and a closure that
-has the same behavior. We’ve added some spaces to line up the relevant parts.
-This illustrates how closure syntax is similar to function syntax except for
-the use of pipes and the amount of syntax that is optional:
+syntax of functions. Here we define a function that adds 1 to its parameter and
+a closure that has the same behavior, for comparison. We’ve added some spaces
+to line up the relevant parts. This illustrates how closure syntax is similar
+to function syntax except for the use of pipes and the amount of syntax that is
+optional:
 
 ```
 fn  add_one_v1   (x: u32) -> u32 { x + 1 }
@@ -201,20 +250,30 @@ let add_one_v4 = |x|               x + 1  ;
 ```
 
 The first line shows a function definition, and the second line shows a fully
-annotated closure definition. The third line removes the type annotations from
-the closure definition, and the fourth line removes the brackets, which are
-optional because the closure body has only one expression. These are all valid
-definitions that will produce the same behavior when they’re called. Calling
-the closures is required for `add_one_v3` and `add_one_v4` to be able to
-compile because the types will be inferred from their usage.
-
-Closure definitions will have one concrete type inferred for each of their
-parameters and for their return value. For instance, Listing 13-3 shows the
-definition of a short closure that just returns the value it receives as a
+annotated closure definition. In the third line, we remove the type annotations
+from the closure definition. In the fourth line, we remove the brackets, which
+are optional because the closure body has only one expression. These are all
+valid definitions that will produce the same behavior when they’re called.
+Evaluating the closures is required for `add_one_v3` and `add_one_v4` to be
+able to compile because the types will be inferred from their usage. This is
+similar to `let v = Vec::new();` needing either type annotations or values of
+some type to be inserted into the `Vec` for Rust to be able to infer the type.
+<!-- I wasn't clear what was meant by "Calling the closures is required for
+`add_one_v3` and `add_one_v4`..." -- I thought these were closures? /LC -->
+<!-- I've changed "Calling" to "Evaluating", does that clear it up? I've also
+added a sentence to have the reader recall how `Vec` works with type
+annotations; it's similar here /Carol -->
+
+For closure definitions, the compiler will infer one concrete type for each of
+their parameters and for their return value. For instance, Listing 13-x shows
+the definition of a short closure that just returns the value it receives as a
 parameter. This closure isn’t very useful except for the purposes of this
-example. Note that we haven’t added any type annotations to the definition: if
-we then try to call the closure twice, using a `String` as an argument the
-first time and a `u32` the second time, we’ll get an error.
+example. Note that we haven’t added any type annotations to the definition.
+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.
+<!-- if we did add type annotations, you mean? Or because we haven't? /LC -->
+<!-- Because we haven't. I've tried to clarify? /Carol -->
 
 Filename: src/main.rs
 
@@ -225,7 +284,7 @@ let s = example_closure(String::from("hello"));
 let n = example_closure(5);
 ```
 
-Listing 13-3: Attempting to call a closure whose types are inferred with two
+Listing 13-x: Attempting to call a closure whose types are inferred with two
 different types
 
 The compiler gives us this error:
@@ -243,7 +302,7 @@ error[E0308]: mismatched types
 The first time we call `example_closure` with the `String` value, the compiler
 infers the type of `x` and the return type of the closure to be `String`. Those
 types are then locked into the closure in `example_closure`, and we get a type
-error if we try to use a different type with the same closure.
+error when we next try to use a different type with the same closure.
 
 ### Capturing References or Moving Ownership
 
@@ -253,11 +312,9 @@ immutably, borrowing mutably, and taking ownership. The closure will decide
 which of these to use based on what the body of the function does with the
 captured values.
 
-Listing 13-4 defines a closure that captures an immutable borrow to the vector
-named `list` because it only needs an immutable borrow to print the value. This
-example also illustrates that a variable can bind to a closure definition, and
-the closure can later be called by using the variable name and parentheses as
-if the variable name were a function name:
+In Listing 13-x, 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
 
@@ -266,20 +323,31 @@ fn main() {
     let list = vec![1, 2, 3];
     println!("Before defining closure: {:?}", list);
 
-    let only_borrows = || println!("From closure: {:?}", list);
+    [1] let only_borrows = || println!("From closure: {:?}", list);
 
     println!("Before calling closure: {:?}", list);
-    only_borrows();
+    only_borrows(); [2]
     println!("After calling closure: {:?}", list);
 }
 ```
 
-Listing 13-4: Defining and calling a closure that captures an immutable borrow
+Listing 13-x: Defining and calling a closure that captures an immutable
+reference
+
+This example also illustrates that a variable can bind to a closure definition
+[1], and we can later call the closure by using the variable name and
+parentheses as if the variable name were a function name [2].
+<!-- That's cool. I'm changing to the active voice here, but I wanted to make
+sure I'm not changing meaning: it is us calling the closure later
+intentionally, right? It's not happening automatically behind the scenes? /LC
+-->
+<!-- Yes, beacuse we've typed `only_borrows()`. I've moved this text after the
+listing and added some wingdings to hopefully be clearer /Carol -->
 
-The `list` is still accessible by the code before the closure definition, after
+Because we can have multiple immutable references to `list` at the same time,
+`list` is still accessible from the code before the closure definition, after
 the closure definition but before the closure is called, and after the closure
-is called because we can have multiple immutable borrows of `list` at the same
-time. This code compiles, runs, and prints:
+is called. This code compiles, runs, and prints:
 
 ```
 Before defining closure: [1, 2, 3]
@@ -288,8 +356,8 @@ From closure: [1, 2, 3]
 After calling closure: [1, 2, 3]
 ```
 
-Next, Listing 13-5 changes the closure definition to need a mutable borrow
-because the closure body adds an element to the `list` vector:
+Next, in Listing 13-x, 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
 
@@ -305,7 +373,7 @@ fn main() {
 }
 ```
 
-Listing 13-5: Defining and calling a closure that captures a mutable borrow
+Listing 13-x: Defining and calling a closure that captures a mutable reference
 
 This code compiles, runs, and prints:
 
@@ -316,48 +384,78 @@ After calling closure: [1, 2, 3, 7]
 
 Note that there’s no longer a `println!` between the definition and the call of
 the `borrows_mutably` closure: when `borrows_mutably` is defined, it captures a
-mutable reference to `list`. After the closure is called, because we don’t use
-the closure again after that point, the mutable borrow ends. Between the
-closure definition and the closure call, an immutable borrow to print isn’t
-allowed because no other borrows are allowed when there’s a mutable borrow. Try
-adding a `println!` there to see what error message you get!
+mutable reference to `list`. We don’t use the closure again after the closure
+is called, so the mutable borrow ends. Between the closure definition and the
+closure call, an immutable borrow to print isn’t allowed because no other
+borrows are allowed when there’s a mutable borrow. Try adding a `println!`
+there to see what error message you get!
 
 If you want to force the closure to take ownership of the values it uses in the
 environment even though the body of the closure doesn’t strictly need
 ownership, you can use the `move` keyword before the parameter list. This
 technique is mostly useful when passing a closure to a new thread to move the
-data so it’s owned by the new thread. We’ll have more examples of `move`
+data so that it’s owned by the new thread. We’ll have more examples of `move`
 closures in Chapter 16 when we talk about concurrency.
 
-### Moving Captured Values Out of the Closure and the `Fn` Traits
-
-Once a closure has captured a reference or moved a value into the closure, the
-code in the body of the function also affects what happens to the references or
-values as a result of calling the function. A closure body can move a captured
-value out of the closure, can mutate the captured value, can neither move nor
-mutate the captured value, or can capture nothing from the environment. The way
-a closure captures and handles values from the environment affects which traits
-the closure implements. The traits are how functions and structs can specify
-what kinds of closures they can use.
-
-Closures will automatically implement one, two, or all three of these `Fn`
-traits, in an additive fashion:
+### Moving Captured Values Out of Closures and the `Fn` Traits
+
+Once a closure has captured a reference or captured ownership of a value where
+the closure is defined (thus affecting what, if anything, is moved *into* the
+closure), the code in the body of the closure defines what happens to the
+references or
+<!-- which function does this refer to -- is a closure always tied to a
+function? I'm thinking of the let closure created earlier. Is "function" here
+just a way to refer to the functionality of the closure? I'm wary of mixing the
+two terms /LC -->
+<!-- This was my mistake, this should say "closure" throughout! Great catch!
+/Carol -->
+values when the closure is evaluated later (thus affecting what, if anything,
+is moved *out of* the closure).
+<!-- do we mean "the references and values that are a result of calling the
+function"? This line confused me a little. Surely it's self-evident that the
+code in the function body affects the value or reference it's called on; I
+think I'm missing something! /LC -->
+<!-- This is an important part of closures that is confusing that I'm trying to
+clear up with this revision. Closure definitions can move references or values
+*in*, then the closure body can move references or values *out*, and we can
+vary these two aspects independently. I'm not sure the edit I've made here
+makes it better or worse? -->
+A closure body can do any of the following: move a captured value out of the
+closure, mutate the captured value, neither move nor mutate the value, or
+capture nothing from the environment to begin with.
+
+The way a closure captures and handles values from the environment affects
+which traits
+<!-- so the closure will automatically implement the traits depending on how we
+set it to handle the values? /LC -->
+<!-- Yup! /Carol-->
+the closure implements, and traits are how functions and structs can specify
+what kinds of closures they can use. Closures will automatically implement one,
+two, or all three of these `Fn` traits, in an additive fashion:
 
 1. `FnOnce` applies to closures that can be called at least once. All closures
-   implement this trait, because all closures can be called. If a closure moves
-   captured values out of its body, then that closure only implements `FnOnce`
-   and not any of the other `Fn` traits, because it can only be called once.
+   implement at least this trait, because all closures can be called. A closure
+   that moves captured values out of its body will only implement `FnOnce`
+   and none of the other `Fn` traits, because it can only be called once.
 2. `FnMut` applies to closures that don’t move captured values out of their
    body, but that might mutate the captured values. These closures can be
    called more than once.
 3. `Fn` applies to closures that don’t move captured values out of their body
-   and that don’t mutate captured values. These closures can be called more
-   than once without mutating their environment, which is important in cases
-   such as calling a closure multiple times concurrently. Closures that don’t
-   capture anything from their environment implement `Fn`.
+   and that don’t mutate captured values, as well as closures that capture
+   nothing from their environment. These closures can be called more than once
+   without mutating their environment, which is important in cases such as
+   calling a closure multiple times concurrently.
+
+<!-- so there isn't a trait for the first action listed above: moving a
+capture value out of the closure? /LC -->
+<!-- There is-- it's `FnOnce`, as stated there: "A closure that moves captured
+values out of its body will only implement `FnOnce`". I think the confusion is
+that the 3rd trait here, `Fn`, applies to the last *two* actions listed above,
+which I tried to express but perhaps wasn't clear enough. I rearranged the text
+in #3 to maybe make it clearer? /Carol -->
 
 Let’s look at the definition of the `unwrap_or_else` method on `Option<T>` that
-we used in Listing 13-6:
+we used in Listing 13-x:
 
 ```
 impl<T> Option<T> {
@@ -378,8 +476,8 @@ Recall that `T` is the generic type representing the type of the value in the
 `unwrap_or_else` function: code that calls `unwrap_or_else` on an
 `Option<String>`, for example, will get a `String`.
 
-Next, notice that the `unwrap_or_else` function has an additional generic type
-parameter, `F`. The `F` type is the type of the parameter named `f`, which is
+Next, notice that the `unwrap_or_else` function has the additional generic type
+parameter `F`. The `F` type is the type of the parameter named `f`, which is
 the closure we provide when calling `unwrap_or_else`.
 
 The trait bound specified on the generic type `F` is `FnOnce() -> T`, which
@@ -399,11 +497,15 @@ of closures and is as flexible as it can be.
 > value is `None`.
 
 Now let’s look at the standard library method `sort_by_key` defined on slices,
-to see how that differs. It takes a closure that implements `FnMut`. The
-closure gets one argument, a reference to the current item in the slice being
-considered, and returns a value of type `K` that can be ordered. This function
-is useful 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
+to see how that differs from `unwrap_or_else` and why `sort_by_key` uses
+`FnMut` instead of `FnOnce` for the trait bound.
+<!-- can you tell us what about this method makes it a good comparison: what's
+the difference we're focusing on? /LC -->
+<!-- Done! /Carol -->
+The closure gets one argument, a reference to the current item in the slice
+being considered, and returns a value of type `K` that can be ordered. This
+function is useful when you want to sort a slice by a particular attribute of
+each item. In Listing 13-x, 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
@@ -417,27 +519,16 @@ struct Rectangle {
 
 fn main() {
     let mut list = [
-        Rectangle {
-            width: 10,
-            height: 1,
-        },
-        Rectangle {
-            width: 3,
-            height: 5,
-        },
-        Rectangle {
-            width: 7,
-            height: 12,
-        },
+        Rectangle { width: 10, height: 1 },
+        Rectangle { width: 3, height: 5 },
+        Rectangle { width: 7, height: 12 },
     ];
 
     list.sort_by_key(|r| r.width);
     println!("{:#?}", list);
 }
 ```
-
-Listing 13-7: Using `sort_by_key` and a closure to sort a list of `Rectangle`
-instances by their `width` value
+Listing 13-x: Using `sort_by_key` to order rectangles by width
 
 This code prints:
 
@@ -463,9 +554,9 @@ the closure multiple times: once for each item in the slice. The closure `|r|
 r.width` doesn’t capture, mutate, or move out anything from its environment, so
 it meets the trait bound requirements.
 
-In contrast, Listing 13-8 shows an example of a closure that only implements
-`FnOnce` because it moves a value out of the environment. The compiler won’t
-let us use this closure with `sort_by_key`:
+In contrast, Listing 13-x 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
 
@@ -478,18 +569,9 @@ struct Rectangle {
 
 fn main() {
     let mut list = [
-        Rectangle {
-            width: 10,
-            height: 1,
-        },
-        Rectangle {
-            width: 3,
-            height: 5,
-        },
-        Rectangle {
-            width: 7,
-            height: 12,
-        },
+        Rectangle { width: 10, height: 1 },
+        Rectangle { width: 3, height: 5 },
+        Rectangle { width: 7, height: 12 },
     ];
 
     let mut sort_operations = vec![];
@@ -503,12 +585,12 @@ fn main() {
 }
 ```
 
-Listing 13-8: Attempting to use an `FnOnce` closure with `sort_by_key`
+Listing 13-x: 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` gets called when sorting `list`. This code
-attempts to do this counting by pushing `value`a `String` from the closure’s
-environmentinto the `sort_operations` vector. The closure captures `value`
+attempts to do this counting by pushing `value`a `String` from the closure’s
+environmentinto the `sort_operations` vector. The closure captures `value`
 then moves `value` out of the closure by transferring ownership of `value` to
 the `sort_operations` vector. This closure can be called once; trying to call
 it a second time wouldn’t work because `value` would no longer be in the
@@ -519,26 +601,30 @@ implement `FnMut`:
 
 ```
 error[E0507]: cannot move out of `value`, a captured variable in an `FnMut` closure
-  --> src/main.rs:27:30
+  --> src/main.rs:18:30
    |
-24 |       let value = String::from("by key called");
+15 |       let value = String::from("by key called");
    |           ----- captured outer variable
-25 |
-26 |       list.sort_by_key(|r| {
+16 |
+17 |       list.sort_by_key(|r| {
    |  ______________________-
-27 | |         sort_operations.push(value);
+18 | |         sort_operations.push(value);
    | |                              ^^^^^ move occurs because `value` has type `String`, which does not implement the `Copy` trait
-28 | |         r.width
-29 | |     });
+19 | |         r.width
+20 | |     });
    | |_____- captured by this `FnMut` closure
 ```
 
 The error points to the line in the closure body that moves `value` out of the
 environment. To fix this, we need to change the closure body so that it doesn’t
-move values out of the environment. If we’re interested in the number of times
-`sort_by_key` is called, keeping a counter in the environment and incrementing
-its value in the closure body is a more straightforward way to calculate that.
-The closure in Listing 13-9 works with `sort_by_key` because it is only
+move values out of the environment. To count the number of times `sort_by_key`
+is called, keeping a counter in the environment and incrementing its value in
+the closure body is a more straightforward way to calculate that.
+<!-- are we interested in this? Are we saying this is basically what we're
+doing, but we're going about it in a roundabout way? /LC -->
+<!-- I'm trying to point out how to fix the example if you wanted this
+behavior, I guess the hypothetical isn't necessary /Carol -->
+The closure in Listing 13-x 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:
 
@@ -553,18 +639,9 @@ struct Rectangle {
 
 fn main() {
     let mut list = [
-        Rectangle {
-            width: 10,
-            height: 1,
-        },
-        Rectangle {
-            width: 3,
-            height: 5,
-        },
-        Rectangle {
-            width: 7,
-            height: 12,
-        },
+        Rectangle { width: 10, height: 1 },
+        Rectangle { width: 3, height: 5 },
+        Rectangle { width: 7, height: 12 },
     ];
 
     let mut num_sort_operations = 0;
@@ -576,12 +653,12 @@ fn main() {
 }
 ```
 
-Listing 13-9: Using an `FnMut` closure with `sort_by_key` is allowed
+Listing 13-x: 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. The next section discusses iterators, and many iterator
-methods take closure arguments. Keep these details of closures in mind as we
-explore iterators!
+make use of closures. In the next section, we’ll discuss iterators. Many
+iterator methods take closure arguments, so keep these closure details in mind
+as we continue!
 
 ## Processing a Series of Items with Iterators
 
@@ -592,7 +669,7 @@ have to reimplement that logic yourself.
 
 In Rust, iterators are *lazy*, meaning they have no effect until you call
 methods that consume the iterator to use it up. For example, the code in
-Listing 13-10 creates an iterator over the items in the vector `v1` by calling
+Listing 13-13 creates an iterator over the items in the vector `v1` by calling
 the `iter` method defined on `Vec<T>`. This code by itself doesn’t do anything
 useful.
 
@@ -602,18 +679,18 @@ let v1 = vec![1, 2, 3];
 let v1_iter = v1.iter();
 ```
 
-Listing 13-10: Creating an iterator
+Listing 13-13: Creating an iterator
 
-Once we’ve created an iterator, we can use it in a variety of ways. In Listing
-3-5 in Chapter 3, we iterated over an array using a `for` loop to execute some
-code on each of its items. Under the hood this implicitly created and then
-consumed an iterator, but we glossed over how exactly that works until now.
+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
+iterated over an array using a `for` loop to execute some code on each of its
+items. Under the hood this implicitly created and then consumed an iterator,
+but we glossed over how exactly that works until now.
 
-The example in Listing 13-11 separates the creation of the iterator from the
-use of the iterator in the `for` loop. The iterator is stored in the `v1_iter`
-variable, and no iteration takes place at that time. 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.
+In the example in Listing 13-14, we separate the creation of the iterator from
+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.
 
 ```
 let v1 = vec![1, 2, 3];
@@ -625,7 +702,7 @@ for val in v1_iter {
 }
 ```
 
-Listing 13-11: Using an iterator in a `for` loop
+Listing 13-14: 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
@@ -665,7 +742,7 @@ The `Iterator` trait only requires implementors to define one method: the
 `next` method, which returns one item of the iterator at a time wrapped in
 `Some` and, when iteration is over, returns `None`.
 
-We can call the `next` method on iterators directly; Listing 13-12 demonstrates
+We can call the `next` method on iterators directly; Listing 13-15 demonstrates
 what values are returned from repeated calls to `next` on the iterator created
 from the vector.
 
@@ -685,7 +762,7 @@ fn iterator_demonstration() {
 }
 ```
 
-Listing 13-12: Calling the `next` method on an iterator
+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
 iterator changes internal state that the iterator uses to keep track of where
@@ -714,7 +791,7 @@ Methods that call `next` are called *consuming adaptors*, because calling them
 uses up the iterator. One example is the `sum` method, which takes ownership of
 the iterator and iterates through the items by repeatedly calling `next`, thus
 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
+total and returns the total when iteration is complete. Listing 13-16 has a
 test illustrating a use of the `sum` method:
 
 Filename: src/lib.rs
@@ -732,7 +809,7 @@ fn iterator_sum() {
 }
 ```
 
-Listing 13-13: Calling the `sum` method to get the total of all items in the
+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` because `sum` takes
@@ -740,16 +817,28 @@ ownership of the iterator we call it on.
 
 ### Methods that Produce Other Iterators
 
-Other methods defined on the `Iterator` trait, known as *iterator adaptors*,
-allow you to change iterators into different kinds of iterators. You can chain
-multiple calls to iterator adaptors to perform complex actions in a readable
-way. But because all iterators are lazy, you have to call one of the consuming
-adaptor methods to get results from calls to iterator adaptors.
-
-Listing 13-14 shows an example of calling the iterator adaptor method `map`,
-which takes a closure to call on each item to produce a new iterator. The
-closure here creates a new iterator in which each item from the vector has been
-incremented by 1. However, this code produces a warning:
+*Iterator adaptors* are methods defined on the `Iterator` trait that don’t
+consume the iterator. Instead, they produce different iterators by changing
+some aspect of the original iterator.
+
+<!-- are all methods defined on Iterator know as iterator adaptors? If so,
+should that term be introduced in the previous section? /LC -->
+<!-- No, only methods on iterator that produce other iterators are adaptors.
+I've tried to make that distinction clearer? /Carol -->
+<!-- is there a quick example of a different kind of iterator you could give? I
+wasn't aware there were different kinds, unless you just mean change them into
+iterators that act on something else? /LC -->
+<!-- Adaptors typically do change an iterator into an iterator with a different
+type, but usually that doesn't matter because the important part is that the
+new type also implents the `Iterator` trait. The iterator typically acts on the
+same items but changes them in different ways. I've tried to rearrange this so
+that the example comes sooner, does this help? /Carol -->
+
+Listing 13-17 shows an example of calling the iterator adaptor method `map`,
+which takes a closure to call on each item as the items are iterated through.
+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
 
@@ -759,9 +848,9 @@ let v1: Vec<i32> = vec![1, 2, 3];
 v1.iter().map(|x| x + 1);
 ```
 
-Listing 13-14: Calling the iterator adaptor `map` to create a new iterator
+Listing 13-17: Calling the iterator adaptor `map` to create a new iterator
 
-The warning we get is this:
+However, this code produces a warning:
 
 ```
 warning: unused `Map` that must be used
@@ -774,15 +863,16 @@ warning: unused `Map` that must be used
   = note: iterators are lazy and do nothing unless consumed
 ```
 
-The code in Listing 13-14 doesn’t do anything; the closure we’ve specified
+The code in Listing 13-17 doesn’t do anything; the closure we’ve specified
 never gets called. The warning reminds us why: iterator adaptors are lazy, and
 we need to consume the iterator here.
 
-To fix this and consume the iterator, we’ll use the `collect` method, which we
-used in Chapter 12 with `env::args` in Listing 12-1. This method consumes the
-iterator and collects the resulting values into a collection data type.
+To fix this warning and consume the iterator, we’ll use the `collect` method,
+which we used in Chapter 12 with `env::args` in Listing 12-1. This method
+consumes the iterator and collects the resulting values into a collection data
+type.
 
-In Listing 13-15, we collect the results of iterating over the iterator that’s
+In Listing 13-18, 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.
 
@@ -796,7 +886,7 @@ let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
 assert_eq!(v2, vec![2, 3, 4]);
 ```
 
-Listing 13-15: Calling the `map` method to create a new iterator and then
+Listing 13-18: 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
@@ -804,16 +894,26 @@ on each item. This is a great example of how closures let you customize some
 behavior while reusing the iteration behavior that the `Iterator` trait
 provides.
 
-### Using Closures that Capture Their Environment
+You can chain multiple calls to iterator adaptors to perform complex actions in
+a readable way. But because all iterators are lazy, you have to call one of the
+consuming adaptor methods to get results from calls to iterator adaptors.
 
-Now that we’ve introduced iterators, we can demonstrate a common use of
-closures that capture their environment by using the `filter` iterator adaptor.
-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.
+### Using Closures that Capture Their Environment
 
-In Listing 13-16, we use `filter` with a closure that captures the `shoe_size`
+Many iterator adapters take closures as arguments, and commonly the closures
+we’ll specify as arguments to iterator adapters will be closures that capture
+their environment.
+<!-- are we saying we use filter to demonstrate some common use, or that using
+filter is the common use? If the former, can you specify what the common usage
+is? /LC -->
+<!-- Iterator adapters commonly use closures that capture their environment,
+I've tried to reword to avoid the ambiguity? /Carol -->
+For this example, we’ll use the `filter` method that takes a closure. The
+closure gets an item from the iterator and returns a Boolean. If the closure
+returns `true`, the value will be included in the iteration produced by
+`filter`. If the closure returns `false`, the value won’t be included.
+
+In Listing 13-19, 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.
 
@@ -870,7 +970,7 @@ mod tests {
 }
 ```
 
-Listing 13-16: Using the `filter` method with a closure that captures
+Listing 13-19: 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
@@ -895,56 +995,56 @@ that have the same size as the value we specified.
 With this new knowledge about iterators, we can improve the I/O project in
 Chapter 12 by using iterators to make places in the code clearer and more
 concise. Let’s look at how iterators can improve our implementation of the
-`Config::new` function and the `search` function.
+`Config::build` function and the `search` function.
 
 ### Removing a `clone` Using an Iterator
 
 In Listing 12-6, we added code that took a slice of `String` values and created
 an instance of the `Config` struct by indexing into the slice and cloning the
-values, allowing the `Config` struct to own those values. In Listing 13-17,
-we’ve reproduced the implementation of the `Config::new` function as it was in
-Listing 12-23:
+values, allowing the `Config` struct to own those values. In Listing 13-24,
+we’ve reproduced the implementation of the `Config::build` function as it was
+in Listing 12-23:
 
 Filename: src/lib.rs
 
 ```
 impl Config {
-    pub fn new(args: &[String]) -> Result<Config, &'static str> {
+    pub fn build(args: &[String]) -> Result<Config, &'static str> {
         if args.len() < 3 {
             return Err("not enough arguments");
         }
 
         let query = args[1].clone();
-        let filename = args[2].clone();
+        let file_path = args[2].clone();
 
-        let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
+        let ignore_case = env::var("IGNORE_CASE").is_ok();
 
         Ok(Config {
             query,
-            filename,
-            case_sensitive,
+            file_path,
+            ignore_case,
         })
     }
 }
 ```
 
-Listing 13-17: Reproduction of the `Config::new` function from Listing 12-23
+Listing 13-24: 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!
 
 We needed `clone` here because we have a slice with `String` elements in the
-parameter `args`, but the `new` function doesn’t own `args`. To return
+parameter `args`, but the `build` function doesn’t own `args`. To return
 ownership of a `Config` instance, we had to clone the values from the `query`
 and `filename` fields of `Config` so the `Config` instance can own its values.
 
-With our new knowledge about iterators, we can change the `new` function to
+With our new knowledge about iterators, we can change the `build` function to
 take ownership of an iterator as its argument instead of borrowing a slice.
 We’ll use the iterator functionality instead of the code that checks the length
 of the slice and indexes into specific locations. This will clarify what the
-`Config::new` function is doing because the iterator will access the values.
+`Config::build` function is doing because the iterator will access the values.
 
-Once `Config::new` takes ownership of the iterator and stops using indexing
+Once `Config::build` takes ownership of the iterator and stops using indexing
 operations that borrow, we can move the `String` values from the iterator into
 `Config` rather than calling `clone` and making a new allocation.
 
@@ -958,8 +1058,8 @@ Filename: src/main.rs
 fn main() {
     let args: Vec<String> = env::args().collect();
 
-    let config = Config::new(&args).unwrap_or_else(|err| {
-        eprintln!("Problem parsing arguments: {}", err);
+    let config = Config::build(&args).unwrap_or_else(|err| {
+        eprintln!("Problem parsing arguments: {err}");
         process::exit(1);
     });
 
@@ -967,16 +1067,16 @@ fn main() {
 }
 ```
 
-We’ll change the start of the `main` function that we had in Listing 12-24 to
-the code in Listing 13-18. This won’t compile until we update `Config::new` as
-well.
+We’ll first change the start of the `main` function that we had in Listing
+12-24 to the code in Listing 13-25, which this time uses an iterator. This
+won’t compile until we update `Config::build` as well.
 
 Filename: src/main.rs
 
 ```
 fn main() {
-    let config = Config::new(env::args()).unwrap_or_else(|err| {
-        eprintln!("Problem parsing arguments: {}", err);
+    let config = Config::build(env::args()).unwrap_or_else(|err| {
+        eprintln!("Problem parsing arguments: {err}");
         process::exit(1);
     });
 
@@ -984,40 +1084,39 @@ fn main() {
 }
 ```
 
-Listing 13-18: Passing the return value of `env::args` to `Config::new`
+Listing 13-25: 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::new`, now
+iterator values into a vector and then passing a slice to `Config::build`, now
 we’re passing ownership of the iterator returned from `env::args` to
-`Config::new` directly.
+`Config::build` directly.
 
-Next, we need to update the definition of `Config::new`. In your I/O project’s
-*src/lib.rs* file, let’s change the signature of `Config::new` to look like
-Listing 13-19. This still won’t compile because we need to update the function
-body.
+Next, we need to update the definition of `Config::build`. In your I/O
+project’s *src/lib.rs* file, let’s change the signature of `Config::build` to
+look like Listing 13-26. This still won’t compile because we need to update the
+function body.
 
 Filename: src/lib.rs
 
 ```
 impl Config {
-    pub fn new(
+    pub fn build(
         mut args: impl Iterator<Item = String>,
     ) -> Result<Config, &'static str> {
         // --snip--
 ```
 
-Listing 13-19: Updating the signature of `Config::new` to expect an iterator
+Listing 13-26: 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
 the `Iterator` trait and returns `String` values.
 
-We’ve updated the signature of the `Config::new` function so the parameter
+We’ve updated the signature of the `Config::build` function so the parameter
 `args` has a generic type with the trait bounds `impl Iterator<Item = String>`
 instead of `&[String]`. This usage of the `impl Trait` syntax we discussed in
-the “Traits as Parameters” section of Chapter 10
-means that `args` can be any type that implements the `Iterator` type and
-returns `String` items.
+the “Traits as Parameters” section of Chapter 10 means that `args` can be any
+type that implements the `Iterator` type and returns `String` items.
 
 Because we’re taking ownership of `args` and we’ll be mutating `args` by
 iterating over it, we can add the `mut` keyword into the specification of the
@@ -1025,15 +1124,15 @@ iterating over it, we can add the `mut` keyword into the specification of the
 
 #### Using `Iterator` Trait Methods Instead of Indexing
 
-Next, we’ll fix the body of `Config::new`. Because `args` implements the
-`Iterator` trait, we know we can call the `next` method on it! Listing 13-20
+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-27
 updates the code from Listing 12-23 to use the `next` method:
 
 Filename: src/lib.rs
 
 ```
 impl Config {
-    pub fn new(
+    pub fn build(
         mut args: impl Iterator<Item = String>,
     ) -> Result<Config, &'static str> {
         args.next();
@@ -1043,23 +1142,23 @@ impl Config {
             None => return Err("Didn't get a query string"),
         };
 
-        let filename = match args.next() {
+        let file_path = match args.next() {
             Some(arg) => arg,
-            None => return Err("Didn't get a file name"),
+            None => return Err("Didn't get a file path"),
         };
 
-        let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
+        let ignore_case = env::var("IGNORE_CASE").is_ok();
 
         Ok(Config {
             query,
-            filename,
-            case_sensitive,
+            file_path,
+            ignore_case,
         })
     }
 }
 ```
 
-Listing 13-20: Changing the body of `Config::new` to use iterator methods
+Listing 13-27: 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
@@ -1072,7 +1171,7 @@ the same thing for the `filename` value.
 ### Making Code Clearer with Iterator Adaptors
 
 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:
+project, which is reproduced here in Listing 13-28 as it was in Listing 12-19:
 
 Filename: src/lib.rs
 
@@ -1090,14 +1189,14 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
 }
 ```
 
-Listing 13-21: The implementation of the `search` function from Listing 12-19
+Listing 13-28: 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
 functional programming style prefers to minimize the amount of mutable state to
 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:
+concurrent access to the `results` vector. Listing 13-29 shows this change:
 
 Filename: src/lib.rs
 
@@ -1110,20 +1209,22 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
 }
 ```
 
-Listing 13-22: Using iterator adaptor methods in the implementation of 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`. Similar to the `filter` example in Listing
-13-16, this code uses the `filter` adaptor to keep only the lines that
+13-19, this code uses the `filter` adaptor to keep only the lines that
 `line.contains(query)` returns `true` for. We then collect the matching lines
 into another vector with `collect`. Much simpler! Feel free to make the same
 change to use iterator methods in the `search_case_insensitive` function as
 well.
 
+### Choosing Between Loops or Iterators
+
 The next logical question is which style you should choose in your own code and
-why: the original implementation in Listing 13-21 or the version using
-iterators in Listing 13-22. Most Rust programmers prefer to use the iterator
+why: 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