]> git.proxmox.com Git - rustc.git/blame - src/doc/book/2018-edition/src/ch13-02-iterators.md
New upstream version 1.31.0~beta.4+dfsg1
[rustc.git] / src / doc / book / 2018-edition / src / ch13-02-iterators.md
CommitLineData
83c7162d
XL
1## Processing a Series of Items with Iterators
2
3The iterator pattern allows you to perform some task on a sequence of items in
4turn. An iterator is responsible for the logic of iterating over each item and
5determining when the sequence has finished. When you use iterators, you don’t
6have to reimplement that logic yourself.
7
8In Rust, iterators are *lazy*, meaning they have no effect until you call
9methods that consume the iterator to use it up. For example, the code in
10Listing 13-13 creates an iterator over the items in the vector `v1` by calling
11the `iter` method defined on `Vec`. This code by itself doesn’t do anything
12useful.
13
14```rust
15let v1 = vec![1, 2, 3];
16
17let v1_iter = v1.iter();
18```
19
20<span class="caption">Listing 13-13: Creating an iterator</span>
21
22Once we’ve created an iterator, we can use it in a variety of ways. In Listing
233-5 in Chapter 3, we used iterators with `for` loops to execute some code on
24each item, although we glossed over what the call to `iter` did until now.
25
26The example in Listing 13-14 separates the creation of the iterator from the
27use of the iterator in the `for` loop. The iterator is stored in the `v1_iter`
28variable, and no iteration takes place at that time. When the `for` loop is
29called using the iterator in `v1_iter`, each element in the iterator is used in
30one iteration of the loop, which prints out each value.
31
32```rust
33let v1 = vec![1, 2, 3];
34
35let v1_iter = v1.iter();
36
37for val in v1_iter {
38 println!("Got: {}", val);
39}
40```
41
42<span class="caption">Listing 13-14: Using an iterator in a `for` loop</span>
43
44In languages that don’t have iterators provided by their standard libraries,
45you would likely write this same functionality by starting a variable at index
460, using that variable to index into the vector to get a value, and
47incrementing the variable value in a loop until it reached the total number of
48items in the vector.
49
50Iterators handle all that logic for you, cutting down on repetitive code you
51could potentially mess up. Iterators give you more flexibility to use the same
52logic with many different kinds of sequences, not just data structures you can
53index into, like vectors. Let’s examine how iterators do that.
54
55### The `Iterator` Trait and the `next` Method
56
57All iterators implement a trait named `Iterator` that is defined in the
58standard library. The definition of the trait looks like this:
59
60```rust
61trait Iterator {
62 type Item;
63
64 fn next(&mut self) -> Option<Self::Item>;
65
66 // methods with default implementations elided
67}
68```
69
70Notice this definition uses some new syntax: `type Item` and `Self::Item`,
71which are defining an *associated type* with this trait. We’ll talk about
72associated types in depth in Chapter 19. For now, all you need to know is that
73this code says implementing the `Iterator` trait requires that you also define
74an `Item` type, and this `Item` type is used in the return type of the `next`
75method. In other words, the `Item` type will be the type returned from the
76iterator.
77
78The `Iterator` trait only requires implementors to define one method: the
79`next` method, which returns one item of the iterator at a time wrapped in
80`Some` and, when iteration is over, returns `None`.
81
82We can call the `next` method on iterators directly; Listing 13-15 demonstrates
83what values are returned from repeated calls to `next` on the iterator created
84from the vector:
85
86<span class="filename">Filename: src/lib.rs</span>
87
88```rust
89#[test]
90fn iterator_demonstration() {
91 let v1 = vec![1, 2, 3];
92
93 let mut v1_iter = v1.iter();
94
95 assert_eq!(v1_iter.next(), Some(&1));
96 assert_eq!(v1_iter.next(), Some(&2));
97 assert_eq!(v1_iter.next(), Some(&3));
98 assert_eq!(v1_iter.next(), None);
99}
100```
101
102<span class="caption">Listing 13-15: Calling the `next` method on an
103iterator</span>
104
105Note that we needed to make `v1_iter` mutable: calling the `next` method on an
106iterator changes internal state that the iterator uses to keep track of where
107it is in the sequence. In other words, this code *consumes*, or uses up, the
108iterator. Each call to `next` eats up an item from the iterator. We didn’t need
109to make `v1_iter` mutable when we used a `for` loop because the loop took
110ownership of `v1_iter` and made it mutable behind the scenes.
111
112Also note that the values we get from the calls to `next` are immutable
113references to the values in the vector. The `iter` method produces an iterator
114over immutable references. If we want to create an iterator that takes
115ownership of `v1` and returns owned values, we can call `into_iter` instead of
116`iter`. Similarly, if we want to iterate over mutable references, we can call
117`iter_mut` instead of `iter`.
118
119### Methods that Consume the Iterator
120
121The `Iterator` trait has a number of different methods with default
122implementations provided by the standard library; you can find out about these
123methods by looking in the standard library API documentation for the `Iterator`
124trait. Some of these methods call the `next` method in their definition, which
125is why you’re required to implement the `next` method when implementing the
126`Iterator` trait.
127
128Methods that call `next` are called *consuming adaptors*, because calling them
129uses up the iterator. One example is the `sum` method, which takes ownership of
130the iterator and iterates through the items by repeatedly calling `next`, thus
131consuming the iterator. As it iterates through, it adds each item to a running
132total and returns the total when iteration is complete. Listing 13-16 has a
133test illustrating a use of the `sum` method:
134
135<span class="filename">Filename: src/lib.rs</span>
136
137```rust
138#[test]
139fn iterator_sum() {
140 let v1 = vec![1, 2, 3];
141
142 let v1_iter = v1.iter();
143
144 let total: i32 = v1_iter.sum();
145
146 assert_eq!(total, 6);
147}
148```
149
150<span class="caption">Listing 13-16: Calling the `sum` method to get the total
151of all items in the iterator</span>
152
153We aren’t allowed to use `v1_iter` after the call to `sum` because `sum` takes
154ownership of the iterator we call it on.
155
156### Methods that Produce Other Iterators
157
158Other methods defined on the `Iterator` trait, known as *iterator adaptors*,
159allow you to change iterators into different kinds of iterators. You can chain
160multiple calls to iterator adaptors to perform complex actions in a readable
161way. But because all iterators are lazy, you have to call one of the consuming
162adaptor methods to get results from calls to iterator adaptors.
163
164Listing 13-17 shows an example of calling the iterator adaptor method `map`,
165which takes a closure to call on each item to produce a new iterator. The
166closure here creates a new iterator in which each item from the vector has been
167incremented by 1. However, this code produces a warning:
168
169<span class="filename">Filename: src/main.rs</span>
170
0bf4aa26 171```rust,not_desired_behavior
83c7162d
XL
172let v1: Vec<i32> = vec![1, 2, 3];
173
174v1.iter().map(|x| x + 1);
175```
176
177<span class="caption">Listing 13-17: Calling the iterator adaptor `map` to
178create a new iterator</span>
179
180The warning we get is this:
181
182```text
183warning: unused `std::iter::Map` which must be used: iterator adaptors are lazy
184and do nothing unless consumed
185 --> src/main.rs:4:5
186 |
1874 | v1.iter().map(|x| x + 1);
188 | ^^^^^^^^^^^^^^^^^^^^^^^^^
189 |
190 = note: #[warn(unused_must_use)] on by default
191```
192
193The code in Listing 13-17 doesn’t do anything; the closure we’ve specified
194never gets called. The warning reminds us why: iterator adaptors are lazy, and
195we need to consume the iterator here.
196
197To fix this and consume the iterator, we’ll use the `collect` method, which we
198used in Chapter 12 with `env::args` in Listing 12-1. This method consumes the
199iterator and collects the resulting values into a collection data type.
200
201In Listing 13-18, we collect the results of iterating over the iterator that’s
202returned from the call to `map` into a vector. This vector will end up
203containing each item from the original vector incremented by 1.
204
205<span class="filename">Filename: src/main.rs</span>
206
207```rust
208let v1: Vec<i32> = vec![1, 2, 3];
209
210let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
211
212assert_eq!(v2, vec![2, 3, 4]);
213```
214
215<span class="caption">Listing 13-18: Calling the `map` method to create a new
216iterator and then calling the `collect` method to consume the new iterator and
217create a vector</span>
218
219Because `map` takes a closure, we can specify any operation we want to perform
220on each item. This is a great example of how closures let you customize some
221behavior while reusing the iteration behavior that the `Iterator` trait
222provides.
223
224### Using Closures that Capture Their Environment
225
226Now that we’ve introduced iterators, we can demonstrate a common use of
227closures that capture their environment by using the `filter` iterator adaptor.
228The `filter` method on an iterator takes a closure that takes each item from
229the iterator and returns a Boolean. If the closure returns `true`, the value
230will be included in the iterator produced by `filter`. If the closure returns
231`false`, the value won’t be included in the resulting iterator.
232
233In Listing 13-19, we use `filter` with a closure that captures the `shoe_size`
234variable from its environment to iterate over a collection of `Shoe` struct
235instances. It will return only shoes that are the specified size.
236
237<span class="filename">Filename: src/lib.rs</span>
238
239```rust
240#[derive(PartialEq, Debug)]
241struct Shoe {
242 size: u32,
243 style: String,
244}
245
246fn shoes_in_my_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
247 shoes.into_iter()
248 .filter(|s| s.size == shoe_size)
249 .collect()
250}
251
252#[test]
253fn filters_by_size() {
254 let shoes = vec![
255 Shoe { size: 10, style: String::from("sneaker") },
256 Shoe { size: 13, style: String::from("sandal") },
257 Shoe { size: 10, style: String::from("boot") },
258 ];
259
260 let in_my_size = shoes_in_my_size(shoes, 10);
261
262 assert_eq!(
263 in_my_size,
264 vec![
265 Shoe { size: 10, style: String::from("sneaker") },
266 Shoe { size: 10, style: String::from("boot") },
267 ]
268 );
269}
270```
271
272<span class="caption">Listing 13-19: Using the `filter` method with a closure
273that captures `shoe_size`</span>
274
275The `shoes_in_my_size` function takes ownership of a vector of shoes and a shoe
276size as parameters. It returns a vector containing only shoes of the specified
277size.
278
279In the body of `shoes_in_my_size`, we call `into_iter` to create an iterator
280that takes ownership of the vector. Then we call `filter` to adapt that
281iterator into a new iterator that only contains elements for which the closure
282returns `true`.
283
284The closure captures the `shoe_size` parameter from the environment and
285compares the value with each shoe’s size, keeping only shoes of the size
286specified. Finally, calling `collect` gathers the values returned by the
287adapted iterator into a vector that’s returned by the function.
288
289The test shows that when we call `shoes_in_my_size`, we get back only shoes
290that have the same size as the value we specified.
291
292### Creating Our Own Iterators with the `Iterator` Trait
293
294We’ve shown that you can create an iterator by calling `iter`, `into_iter`, or
295`iter_mut` on a vector. You can create iterators from the other collection
296types in the standard library, such as hash map. You can also create iterators
297that do anything you want by implementing the `Iterator` trait on your own
298types. As previously mentioned, the only method you’re required to provide a
299definition for is the `next` method. Once you’ve done that, you can use all
300other methods that have default implementations provided by the `Iterator`
301trait!
302
303To demonstrate, let’s create an iterator that will only ever count from 1 to 5.
304First, we’ll create a struct to hold some values. Then we’ll make this struct
305into an iterator by implementing the `Iterator` trait and using the values in
306that implementation.
307
308Listing 13-20 has the definition of the `Counter` struct and an associated
309`new` function to create instances of `Counter`:
310
311<span class="filename">Filename: src/lib.rs</span>
312
313```rust
314struct Counter {
315 count: u32,
316}
317
318impl Counter {
319 fn new() -> Counter {
320 Counter { count: 0 }
321 }
322}
323```
324
325<span class="caption">Listing 13-20: Defining the `Counter` struct and a `new`
326function that creates instances of `Counter` with an initial value of 0 for
327`count`</span>
328
329The `Counter` struct has one field named `count`. This field holds a `u32`
330value that will keep track of where we are in the process of iterating from 1
331to 5. The `count` field is private because we want the implementation of
332`Counter` to manage its value. The `new` function enforces the behavior of
333always starting new instances with a value of 0 in the `count` field.
334
335Next, we’ll implement the `Iterator` trait for our `Counter` type by defining
336the body of the `next` method to specify what we want to happen when this
337iterator is used, as shown in Listing 13-21:
338
339<span class="filename">Filename: src/lib.rs</span>
340
341```rust
342# struct Counter {
343# count: u32,
344# }
345#
346impl Iterator for Counter {
347 type Item = u32;
348
349 fn next(&mut self) -> Option<Self::Item> {
350 self.count += 1;
351
352 if self.count < 6 {
353 Some(self.count)
354 } else {
355 None
356 }
357 }
358}
359```
360
361<span class="caption">Listing 13-21: Implementing the `Iterator` trait on our
362`Counter` struct</span>
363
364We set the associated `Item` type for our iterator to `u32`, meaning the
365iterator will return `u32` values. Again, don’t worry about associated types
366yet, we’ll cover them in Chapter 19.
367
368We want our iterator to add 1 to the current state, so we initialized `count`
369to 0 so it would return 1 first. If the value of `count` is less than 6, `next`
370will return the current value wrapped in `Some`, but if `count` is 6 or higher,
371our iterator will return `None`.
372
373#### Using Our `Counter` Iterator’s `next` Method
374
375Once we’ve implemented the `Iterator` trait, we have an iterator! Listing 13-22
376shows a test demonstrating that we can use the iterator functionality of our
377`Counter` struct by calling the `next` method on it directly, just as we did
378with the iterator created from a vector in Listing 13-15.
379
380<span class="filename">Filename: src/lib.rs</span>
381
382```rust
383# struct Counter {
384# count: u32,
385# }
386#
387# impl Iterator for Counter {
388# type Item = u32;
389#
390# fn next(&mut self) -> Option<Self::Item> {
391# self.count += 1;
392#
393# if self.count < 6 {
394# Some(self.count)
395# } else {
396# None
397# }
398# }
399# }
400#
401#[test]
402fn calling_next_directly() {
403 let mut counter = Counter::new();
404
405 assert_eq!(counter.next(), Some(1));
406 assert_eq!(counter.next(), Some(2));
407 assert_eq!(counter.next(), Some(3));
408 assert_eq!(counter.next(), Some(4));
409 assert_eq!(counter.next(), Some(5));
410 assert_eq!(counter.next(), None);
411}
412```
413
414<span class="caption">Listing 13-22: Testing the functionality of the `next`
415method implementation</span>
416
417This test creates a new `Counter` instance in the `counter` variable and then
418calls `next` repeatedly, verifying that we have implemented the behavior we
419want this iterator to have: returning the values from 1 to 5.
420
421#### Using Other `Iterator` Trait Methods
422
423We implemented the `Iterator` trait by defining the `next` method, so we
424can now use any `Iterator` trait method’s default implementations as defined in
425the standard library, because they all use the `next` method’s functionality.
426
427For example, if for some reason we wanted to take the values produced by an
428instance of `Counter`, pair them with values produced by another `Counter`
429instance after skipping the first value, multiply each pair together, keep only
430those results that are divisible by 3, and add all the resulting values
431together, we could do so, as shown in the test in Listing 13-23:
432
433<span class="filename">Filename: src/lib.rs</span>
434
435```rust
436# struct Counter {
437# count: u32,
438# }
439#
440# impl Counter {
441# fn new() -> Counter {
442# Counter { count: 0 }
443# }
444# }
445#
446# impl Iterator for Counter {
447# // Our iterator will produce u32s
448# type Item = u32;
449#
450# fn next(&mut self) -> Option<Self::Item> {
451# // increment our count. This is why we started at zero.
452# self.count += 1;
453#
454# // check to see if we've finished counting or not.
455# if self.count < 6 {
456# Some(self.count)
457# } else {
458# None
459# }
460# }
461# }
462#
463#[test]
464fn using_other_iterator_trait_methods() {
465 let sum: u32 = Counter::new().zip(Counter::new().skip(1))
466 .map(|(a, b)| a * b)
467 .filter(|x| x % 3 == 0)
468 .sum();
469 assert_eq!(18, sum);
470}
471```
472
473<span class="caption">Listing 13-23: Using a variety of `Iterator` trait
474methods on our `Counter` iterator</span>
475
476Note that `zip` produces only four pairs; the theoretical fifth pair `(5,
477None)` is never produced because `zip` returns `None` when either of its input
478iterators return `None`.
479
480All of these method calls are possible because we specified how the `next`
481method works, and the standard library provides default implementations for
482other methods that call `next`.