]> git.proxmox.com Git - rustc.git/blame - src/doc/book/second-edition/src/ch13-02-iterators.md
New upstream version 1.19.0+dfsg1
[rustc.git] / src / doc / book / second-edition / src / ch13-02-iterators.md
CommitLineData
7cac9316
XL
1## Processing a Series of Items with Iterators
2
3<!-- From reading on, it seems like an iterator is useless without the methods
4we use it with --- I think this is an important point to make early, I did find
5it difficult to know what an iterator actually was throughout, and how it
6depends on these other methods. Can you add something to this effect? -->
7<!-- Reiterating the need for a clear definition of an iterator here--it seems
8like an item that's used in iteration rather than something that performs the
9process of iteration itself, is that right? Like a counter passed from element
10to element? Can we define this at the begin of the iterator section? -->
11<!-- I've added an explanation along these lines, does this help? /Carol -->
12
13The iterator pattern allows you to perform some task on a sequence of items in
14turn. An *iterator* is responsible for the logic around iterating over each item
15in the sequence and determining when the sequence has finished. When we use
16iterators, we don't have to reimplement that logic ourselves.
17
18In Rust, iterators are *lazy*, which means they have no effect until we call
19methods on them that consume the iterator to use it up. For example, the code
20in Listing 13-13 creates an iterator over the items in the vector `v1` by
21calling the `iter` method defined on `Vec`. This code by itself doesn't do
22anything useful:
cc61c64b 23
7cac9316
XL
24```rust
25let v1 = vec![1, 2, 3];
26
27let v1_iter = v1.iter();
28```
29
30<span class="caption">Listing 13-13: Creating an iterator; this by itself isn't
31useful</span>
32
33After creating an iterator, we can choose to use it in a variety of ways. In
34Listing 3-6, we actually used iterators with `for` loops to execute some code
35on each item, though we glossed over what the call to `iter` did until now. The
36example in Listing 13-14 separates the creation of the iterator from the use of
37the iterator in the `for` loop. The iterator is stored in the `v1_iter`
38variable, and no iteration takes place at that time. Once the `for` loop is
39called using the iterator in `v1_iter`, then each element in the iterator is
40used in one iteration of the loop, which prints out each value:
cc61c64b
XL
41
42```rust
43let v1 = vec![1, 2, 3];
44
7cac9316 45let v1_iter = v1.iter();
cc61c64b 46
7cac9316
XL
47for val in v1_iter {
48 println!("Got: {}", val);
49}
cc61c64b
XL
50```
51
7cac9316
XL
52<span class="caption">Listing 13-13: Making use of an iterator in a `for`
53loop</span>
cc61c64b 54
7cac9316
XL
55In languages that don't have iterators provided by their standard libraries, we
56would likely write this same functionality by starting a variable at index 0,
57using that variable to index into the vector to get a value, and incrementing
58the variable value in a loop until its value gets up to the total number of
59items in the vector. Iterators take care of all of that logic for us, which
60cuts down on the repetitive code we would have to write and potentially mess up.
61In addition, the way iterators are implemented gives us more flexibility to
62use the same logic with many different kinds of sequences, not just data
63structures that we can index into like vectors. Let's see how iterators do that.
64
65### The `Iterator` trait and the `next` method
66
67Iterators all implement a trait named `Iterator` that is defined in the
68standard library. The definition of the trait looks like this:
69
70```rust
71trait Iterator {
72 type Item;
73
74 fn next(&mut self) -> Option<Self::Item>;
75
76 // methods with default implementations elided
77}
78```
cc61c64b 79
7cac9316
XL
80You'll notice some new syntax that we haven't covered yet: `type Item` and
81`Self::Item`, which are defining an *associated type* with this trait. We'll
82talk about associated types in depth in Chapter 19, but for now, all you need
83to know is that this code says implementing `Iterator` trait requires that you
84also define an `Item` type, and this `Item` type is used in the return type of
85the `next` method. In other words, the `Item` type will be the type of element
86that's returned from the iterator.
87
88The `next` method is the only method that the `Iterator` trait requires
89implementers of the trait to define. `next` returns one item of the iterator
90at a time wrapped in `Some`, and when iteration is over, it returns `None`.
91We can call the `next` method on iterators directly if we'd like; Listing 13-14
92has a test that demonstrates the values we'd get on repeated calls to `next`
93on the iterator created from the vector:
94
95<span class="filename">Filename: src/lib.rs</span>
96
97```rust,test_harness
98#[test]
99fn iterator_demonstration() {
100 let v1 = vec![1, 2, 3];
101
102 let mut v1_iter = v1.iter();
103
104 assert_eq!(v1_iter.next(), Some(&1));
105 assert_eq!(v1_iter.next(), Some(&2));
106 assert_eq!(v1_iter.next(), Some(&3));
107 assert_eq!(v1_iter.next(), None);
108}
109```
110
111<span class="caption">Listing 13-14: Calling the `next` method on an
112iterator</span>
113
114Note that we needed to make `v1_iter` mutable: calling the `next` method on an
115iterator changes the iterator's state that keeps track of where it is in the
116sequence. Put another way, this code *consumes*, or uses up, the iterator. Each
117call to `next` eats up an item from the iterator.
118
119Also note that the values we get from the calls to `next` are immutable
120references to the values in the vector. The `iter` method produces an iterator
121over immutable references. If we wanted to create an iterator that takes
122ownership of `v1` and returns owned values, we can call `into_iter` instead of
123`iter`. Similarly, if we want to iterate over mutable references, we can call
124`iter_mut` instead of `iter`.
125
126### Methods in the `Iterator` Trait that Consume the Iterator
127
128<!-- Can you explain what it is you mean by "consumes" an iterator here? It
129doesn't look like we do in this section, I think that's important to lay that
130out clearly -->
131<!-- This next paragraph doesn't give much away to me I'm afraid, not being
132clear what we mean by *consume* at this point. Is a consuming adaptor like a
133catalyst? -->
134<!-- I hope this section addresses these comments you had /Carol -->
135
136The `Iterator` trait has a number of different methods with default
137implementations provided for us by the standard library; you can find out all
138about these methods by looking in the standard library API documentation for
139the `Iterator` trait. Some of these methods call the `next` method in their
140definition, which is why we're required to implement the `next` method when
141implementing the `Iterator` trait.
142
143<!-- Is there somewhere they can learn about all the methods and what they do,
144how to use them? This seems like a good sample example, and if we can broaden
145it out that would be really helpful -->
146<!-- I've moved this comment here since you made this comment on the last
147version of this chapter right after a spot where we mentioned looking at the
148standard library API documentation for the iterator trait, like we're now doing
149in the above paragraph. That's where the reader should go to learn about
150all the methods and what they do and how to use them. Can you elaborate on why
151that wasn't clear in the previous version of the chapter? Is there a reason why
152the standard library API documentation didn't sound like that place to go?
153/Carol -->
154
155The methods that call the `next` method are called *consuming adaptors*, since
156calling them uses up the iterator. An example of a consuming adaptor is the
157`sum` method. This method takes ownership of the iterator and iterates through
158the items by repeatedly calling `next`, thus consuming the iterator. As it
159iterates through each item, it adds each item to a running total and returns
160the total when iteration has completed. Listing 13-15 has a test illustrating a
161use of the `sum` method:
162
163<span class="filename">Filename: src/lib.rs</span>
164
165```rust
166#[test]
167fn iterator_sum() {
168 let v1 = vec![1, 2, 3];
cc61c64b 169
7cac9316 170 let v1_iter = v1.iter();
cc61c64b 171
7cac9316 172 let total: i32 = v1_iter.sum();
cc61c64b 173
7cac9316
XL
174 assert_eq!(total, 6);
175}
176```
177
178<span class="caption">Listing 13-15: Calling the `sum` method to get the total
179of all items in the iterator</span>
cc61c64b 180
7cac9316
XL
181We aren't allowed to use `v1_iter` after the call to `sum` since `sum` takes
182ownership of the iterator we call it on.
cc61c64b 183
7cac9316 184### Methods in the `Iterator` Trait that Produce Other Iterators
cc61c64b 185
7cac9316
XL
186Another kind of method defined on the `Iterator` trait are methods that produce
187other iterators. These methods are called *iterator adaptors* and allow us to
188change iterators into different kind of iterators. We can chain multiple calls
189to iterator adaptors. Because all iterators are lazy, however, we have to
190call one of the consuming adaptor methods in order to get results from calls
191to iterator adaptors. Listing 13-16 shows an example of calling the iterator
192adaptor method `map`, which takes a closure that `map` will call on each
193item in order to produce a new iterator in which each item from the vector has
194been incremented by 1. This code produces a warning, though:
195
196<span class="filename">Filename: src/main.rs</span>
cc61c64b
XL
197
198```rust
199let v1: Vec<i32> = vec![1, 2, 3];
200
7cac9316 201v1.iter().map(|x| x + 1);
cc61c64b
XL
202```
203
7cac9316
XL
204<span class="caption">Listing 13-16: Calling the iterator adapter `map` to
205create a new iterator</span>
206
207The warning we get is:
cc61c64b
XL
208
209```text
210warning: unused result which must be used: iterator adaptors are lazy and do
7cac9316 211nothing unless consumed
cc61c64b
XL
212 --> src/main.rs:4:1
213 |
7cac9316 2144 | v1.iter().map(|x| x + 1);
cc61c64b 215 | ^^^^^^^^^^^^^^^^^^^^^^^^^
7cac9316
XL
216 |
217 = note: #[warn(unused_must_use)] on by default
cc61c64b
XL
218```
219
7cac9316
XL
220The code in Listing 13-16 isn't actually doing anything; the closure we've
221specified never gets called. The warning reminds us why: iterator adaptors are
222lazy, and we probably meant to consume the iterator here.
cc61c64b 223
7cac9316
XL
224In order to fix this warning and consume the iterator to get a useful result,
225we're going to use the `collect` method, which we saw briefly in Chapter 12.
226This method consumes the iterator and collects the resulting values into a
227data structure. In Listing 13-17, we're going to collect the results of
228iterating over the iterator returned from the call to `map` into a vector that
229will contain each item from the original vector incremented by 1:
cc61c64b 230
7cac9316 231<span class="filename">Filename: src/main.rs</span>
cc61c64b
XL
232
233```rust
7cac9316 234let v1: Vec<i32> = vec![1, 2, 3];
cc61c64b 235
7cac9316
XL
236let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
237
238assert_eq!(v2, vec![2, 3, 4]);
239```
240
241<span class="caption">Listing 13-17: Calling the `map` method to create a new
242iterator, then calling the `collect` method to consume the new iterator and
243create a vector</span>
244
245Because `map` takes a closure, we can specify any operation that we want to
246perform on each item that we iterate over. This is a great example of how using
247closures lets us customize some behavior while reusing the iteration behavior
248that the `Iterator` trait provides.
249
250<!-- I'm not clear from this last sentence which part is iterating through each
251element, iter or map? What is map actually doing?-->
252<!--Ah, I'm afraid I completely failed to follow this. What is the second
253iterator for? I'm still not clear on what map does, can you expand on this? It
254seems crucial to using iterators. Map applies the iterator to each element,
255which applies the closure?
256
257Also, to generalize this discussion a bit, would you ever use iter without map?
258-->
259<!-- I hope this new breakdown/rearranging has cleared up these comments you
260had on the last version of this chapter about the difference between
261iter and map. I hope the added examples where we've used iter without map have
262cleared up the last question. /Carol -->
263
264### Using Closures that Capture their Environment with Iterators
265
266Now that we've introduced iterators, we can demonstrate a common use of
267closures that capture their environment by using the `filter` iterator adapter.
268The `filter` method on an iterator takes a closure that takes each item from
269the iterator and returns a boolean. If the closure returns `true`, the value
270will be included in the iterator produced by `filter`. If the closure returns
271`false`, the value won't be included in the resulting iterator. Listing 13-18
272demonstrates using `filter` with a closure that captures the `shoe_size`
273variable from its environment in order to iterate over a collection of `Shoe`
274struct instances in order to return only shoes that are the specified size:
275
276<span class="filename">Filename: src/lib.rs</span>
277
278```rust,test_harness
279#[derive(PartialEq, Debug)]
280struct Shoe {
281 size: i32,
282 style: String,
283}
284
285fn shoes_in_my_size(shoes: Vec<Shoe>, shoe_size: i32) -> Vec<Shoe> {
286 shoes.into_iter()
287 .filter(|s| s.size == shoe_size)
288 .collect()
289}
290
291#[test]
292fn filters_by_size() {
293 let shoes = vec![
294 Shoe { size: 10, style: String::from("sneaker") },
295 Shoe { size: 13, style: String::from("sandal") },
296 Shoe { size: 10, style: String::from("boot") },
297 ];
298
299 let in_my_size = shoes_in_my_size(shoes, 10);
300
301 assert_eq!(
302 in_my_size,
303 vec![
304 Shoe { size: 10, style: String::from("sneaker") },
305 Shoe { size: 10, style: String::from("boot") },
306 ]
307 );
cc61c64b
XL
308}
309```
310
7cac9316
XL
311<span class="caption">Listing 13-18: Using the `filter` method with a closure
312that captures `shoe_size`</span>
313
314<!-- Will add wingdings in libreoffice /Carol -->
315
316The `shoes_in_my_size` function takes ownership of a vector of shoes and a shoe
317size as parameters. It returns a vector containing only shoes of the specified
318size. In the body of `shoes_in_my_size`, we call `into_iter` to create an
319iterator that takes ownership of the vector. Then we call `filter` to adapt
320that iterator into a new iterator that only contains elements for which the
321closure returns `true`. The closure we've specified captures the `shoe_size`
322parameter from the environment and uses the value to compare with each shoe's
323size to only keep shoes that are of the size specified. Finally, calling
324`collect` gathers the values returned by the adapted iterator into a vector
325that the function returns.
326
327The test shows that when we call `shoes_in_my_size`, we only get back shoes
328that have the same size as the value we specified.
329
330### Implementing the `Iterator` Trait to Create Our Own Iterators
331
332<!-- So it seems like we are creating a program with an iterator inside, is
333that right? I assumed the whole thing we were making was an iterator at first,
334which lead to a few confusions, can you lay it out up front? -->
335<!-- I'm not sure what you mean here, can you elaborate on what the distinction
336is to you between "a program with an iterator inside" and "whole thing we were
337making was an iterator"? I don't understand what you mean by these terms so I'm
338not sure how to clear this up. /Carol -->
339
340We've shown that we can create an iterator by calling `iter`, `into_iter`, or
341`iter_mut` on a vector. We can also create iterators from the other collection
342types in the standard library, such as hash map. Additionally, we can implement
343the `Iterator` trait in order to create iterators that do anything we want.
344As previously mentioned, the only method we're required to provide a definition
345for is the `next` method. Once we've done that, we can use all the other
346methods that have default implementations provided by the `Iterator` trait on
347our iterator!
348
349<!-- NEXT PARAGRAPH WRAPPED WEIRD INTENTIONALLY SEE #199 -->
350
351The iterator we're going to create is one that will only ever count from 1
352to 5. First, we'll create a struct to hold on to some values, and then we'll
353make this struct into an iterator by implementing the `Iterator` trait and use
354the values in that implementation.
355
356Listing 13-19 has the definition of the `Counter` struct and an associated
357`new` function to create instances of `Counter`:
358
359<span class="filename">Filename: src/lib.rs</span>
cc61c64b
XL
360
361```rust
362struct Counter {
363 count: u32,
364}
365
366impl Counter {
367 fn new() -> Counter {
368 Counter { count: 0 }
369 }
370}
371```
372
7cac9316
XL
373<span class="caption">Listing 13-19: Defining the `Counter` struct and a `new`
374function that creates instances of `Counter` with an initial value of 0 for
375`count`</span>
376
377<!-- Could you add a filename here? I think that will help the reader keep
378track of what they're working on. Can you also just sum up in a line what this
379code has accomplished so far? I moved this down from above the code, if this
380will do? -->
381<!-- Done /Carol -->
382
383The `Counter` struct has one field named `count`. This field holds a `u32`
384value that will keep track of where we are in the process of iterating from 1
385to 5. The `count` field is private since we want the implementation of
386`Counter` to manage its value. The `new` function enforces the behavior we want
387of always starting new instances with a value of 0 in the `count` field.
388
389<!-- Why define the new method, if it isn't necessary? Or is that what this
390next line is telling us? -->
391<!-- So does this code just initialize it with 0? Is that jat { count: 0 }
392does?-->
393<!-- I've rearranged to make this clearer /Carol -->
394
cc61c64b 395Next, we're going to implement the `Iterator` trait for our `Counter` type by
7cac9316
XL
396defining the body of the `next` method to specify what we want to happen when
397this iterator is used, as shown in Listing 13-20:
398
399<span class="filename">Filename: src/lib.rs</span>
cc61c64b
XL
400
401```rust
402# struct Counter {
403# count: u32,
404# }
405#
406impl Iterator for Counter {
cc61c64b
XL
407 type Item = u32;
408
409 fn next(&mut self) -> Option<Self::Item> {
cc61c64b
XL
410 self.count += 1;
411
cc61c64b
XL
412 if self.count < 6 {
413 Some(self.count)
414 } else {
415 None
416 }
417 }
418}
419```
420
7cac9316 421<span class="caption">Listing 13-20: Implementing the `Iterator` trait on our
cc61c64b
XL
422`Counter` struct</span>
423
424<!-- I will add wingdings in libreoffice /Carol -->
425
7cac9316
XL
426We set the associated `Item` type for our iterator to `u32`, meaning the
427iterator will return `u32` values. Again, don't worry about associated types
428yet, we'll be covering them in Chapter 19. We want our iterator to add one to
429the current state, which is why we initialized `count` to 0: we want our
430iterator to return one first. If the value of `count` is less than six, `next`
431will return the current value wrapped in `Some`, but if `count` is six or
432higher, our iterator will return `None`.
cc61c64b 433
7cac9316 434#### Using Our `Counter` Iterator's `next` Method
cc61c64b 435
7cac9316
XL
436Once we've implemented the `Iterator` trait, we have an iterator! Listing 13-21
437shows a test demonstrating that we can use the iterator functionality our
438`Counter` struct now has by calling the `next` method on it directly, just like
439we did with the iterator created from a vector in Listing 13-14:
cc61c64b 440
7cac9316 441<span class="filename">Filename: src/lib.rs</span>
cc61c64b 442
7cac9316
XL
443```rust
444# struct Counter {
445# count: u32,
446# }
447#
448# impl Iterator for Counter {
449# type Item = u32;
450#
451# fn next(&mut self) -> Option<Self::Item> {
452# self.count += 1;
453#
454# if self.count < 6 {
455# Some(self.count)
456# } else {
457# None
458# }
459# }
460# }
461#
462#[test]
463fn calling_next_directly() {
464 let mut counter = Counter::new();
465
466 assert_eq!(counter.next(), Some(1));
467 assert_eq!(counter.next(), Some(2));
468 assert_eq!(counter.next(), Some(3));
469 assert_eq!(counter.next(), Some(4));
470 assert_eq!(counter.next(), Some(5));
471 assert_eq!(counter.next(), None);
472}
473```
cc61c64b 474
7cac9316
XL
475<span class="caption">Listing 13-21: Testing the functionality of the `next`
476method implementation</span>
477
478This test creates a new `Counter` instance in the `counter` variable and then
479calls `next` repeatedly, verifying that we have implemented the behavior we
480want this iterator to have of returning the values from 1 to 5.
481
482<!-- So if I have this right, the first line creates a new Counter called
483counter, and the rest of them merely call counter with next, store it in x, and
484then print x? And we have to do that 5 times to get the 1-5 count? Phew, could
485you wrap that up if indeed it is correct!) and sum up here? -->
486<!-- I decided to change this into a test rather than printing out values, and
487I added some summary text about what the test is doing. Is this clearer? /Carol
488-->
489
490#### Using Other `Iterator` Trait Methods on Our Iterator
491
492Because we implemented the `Iterator` trait by defining the `next` method, we
493can now use any `Iterator` trait method's default implementations that the
494standard library has defined, since they all use the `next` method's
495functionality.
496
497<!-- So we can't just use these methods anyway? It seems like we did earlier,
498but here we have to use next first, before we cam access these methods? -->
499<!-- No, we don't have to *use* `next` before we can use the other methods, we
500have to *define* `next` before we can use the other methods. I hope the various
501rewordings and reworkings have made this clearer by this point. /Carol -->
502
503<!-- below: once you've done what, defined a default implementation? Only then
504can you use other adapters, is that what we're saying? And I'm still not clear
505on what an adapter does/means, as opposed to a method, or consumer, at this
506point. -->
507<!-- I hope this comment has been cleared up too /Carol -->
508
509For example, if for some reason we wanted to take the values that an instance
510of `Counter` produces, pair those values with values produced by another
511`Counter` instance after skipping the first value that instance produces,
512multiply each pair together, keep only those results that are divisible by
513three, and add all the resulting values together, we could do so as shown in
514the test in Listing 13-22:
515
516<span class="filename">Filename: src/lib.rs</span>
cc61c64b
XL
517
518```rust
519# struct Counter {
520# count: u32,
521# }
522#
523# impl Counter {
524# fn new() -> Counter {
525# Counter { count: 0 }
526# }
527# }
528#
529# impl Iterator for Counter {
530# // Our iterator will produce u32s
531# type Item = u32;
532#
533# fn next(&mut self) -> Option<Self::Item> {
534# // increment our count. This is why we started at zero.
535# self.count += 1;
536#
537# // check to see if we've finished counting or not.
538# if self.count < 6 {
539# Some(self.count)
540# } else {
541# None
542# }
543# }
544# }
7cac9316
XL
545#
546#[test]
547fn using_other_iterator_trait_methods() {
548 let sum: u32 = Counter::new().zip(Counter::new().skip(1))
549 .map(|(a, b)| a * b)
550 .filter(|x| x % 3 == 0)
551 .sum();
552 assert_eq!(18, sum);
553}
cc61c64b
XL
554```
555
7cac9316
XL
556<span class="caption">Listing 13-22: Using a variety of `Iterator` trait
557methods on our `Counter` iterator</span>
558
cc61c64b
XL
559Note that `zip` produces only four pairs; the theoretical fifth pair `(5,
560None)` is never produced because `zip` returns `None` when either of its input
561iterators return `None`.
562
563All of these method calls are possible because we implemented the `Iterator`
7cac9316
XL
564trait by specifying how the `next` method works and the standard library
565provides default implementations for other methods that call `next`.