]> git.proxmox.com Git - rustc.git/blame - src/doc/book/src/ch13-02-iterators.md
Merge tag 'debian/1.52.1+dfsg1-1_exp2' into proxmox/buster
[rustc.git] / src / doc / book / src / ch13-02-iterators.md
CommitLineData
13cf67c4
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
9fa01778 11the `iter` method defined on `Vec<T>`. This code by itself doesn’t do anything
13cf67c4
XL
12useful.
13
14```rust
74b04a01 15{{#rustdoc_include ../listings/ch13-functional-features/listing-13-13/src/main.rs:here}}
13cf67c4
XL
16```
17
18<span class="caption">Listing 13-13: Creating an iterator</span>
19
20Once we’ve created an iterator, we can use it in a variety of ways. In Listing
213-5 in Chapter 3, we used iterators with `for` loops to execute some code on
22each item, although we glossed over what the call to `iter` did until now.
23
24The example in Listing 13-14 separates the creation of the iterator from the
25use of the iterator in the `for` loop. The iterator is stored in the `v1_iter`
26variable, and no iteration takes place at that time. When the `for` loop is
27called using the iterator in `v1_iter`, each element in the iterator is used in
28one iteration of the loop, which prints out each value.
29
30```rust
74b04a01 31{{#rustdoc_include ../listings/ch13-functional-features/listing-13-14/src/main.rs:here}}
13cf67c4
XL
32```
33
34<span class="caption">Listing 13-14: Using an iterator in a `for` loop</span>
35
36In languages that don’t have iterators provided by their standard libraries,
37you would likely write this same functionality by starting a variable at index
380, using that variable to index into the vector to get a value, and
39incrementing the variable value in a loop until it reached the total number of
40items in the vector.
41
42Iterators handle all that logic for you, cutting down on repetitive code you
43could potentially mess up. Iterators give you more flexibility to use the same
44logic with many different kinds of sequences, not just data structures you can
45index into, like vectors. Let’s examine how iterators do that.
46
47### The `Iterator` Trait and the `next` Method
48
49All iterators implement a trait named `Iterator` that is defined in the
50standard library. The definition of the trait looks like this:
51
52```rust
9fa01778 53pub trait Iterator {
13cf67c4
XL
54 type Item;
55
56 fn next(&mut self) -> Option<Self::Item>;
57
58 // methods with default implementations elided
59}
60```
61
62Notice this definition uses some new syntax: `type Item` and `Self::Item`,
63which are defining an *associated type* with this trait. We’ll talk about
64associated types in depth in Chapter 19. For now, all you need to know is that
65this code says implementing the `Iterator` trait requires that you also define
66an `Item` type, and this `Item` type is used in the return type of the `next`
67method. In other words, the `Item` type will be the type returned from the
68iterator.
69
70The `Iterator` trait only requires implementors to define one method: the
71`next` method, which returns one item of the iterator at a time wrapped in
72`Some` and, when iteration is over, returns `None`.
73
74We can call the `next` method on iterators directly; Listing 13-15 demonstrates
75what values are returned from repeated calls to `next` on the iterator created
9fa01778 76from the vector.
13cf67c4
XL
77
78<span class="filename">Filename: src/lib.rs</span>
79
fc512014 80```rust,noplayground
74b04a01 81{{#rustdoc_include ../listings/ch13-functional-features/listing-13-15/src/lib.rs:here}}
13cf67c4
XL
82```
83
84<span class="caption">Listing 13-15: Calling the `next` method on an
85iterator</span>
86
87Note that we needed to make `v1_iter` mutable: calling the `next` method on an
88iterator changes internal state that the iterator uses to keep track of where
89it is in the sequence. In other words, this code *consumes*, or uses up, the
90iterator. Each call to `next` eats up an item from the iterator. We didn’t need
91to make `v1_iter` mutable when we used a `for` loop because the loop took
92ownership of `v1_iter` and made it mutable behind the scenes.
93
94Also note that the values we get from the calls to `next` are immutable
95references to the values in the vector. The `iter` method produces an iterator
96over immutable references. If we want to create an iterator that takes
97ownership of `v1` and returns owned values, we can call `into_iter` instead of
98`iter`. Similarly, if we want to iterate over mutable references, we can call
99`iter_mut` instead of `iter`.
100
101### Methods that Consume the Iterator
102
103The `Iterator` trait has a number of different methods with default
104implementations provided by the standard library; you can find out about these
105methods by looking in the standard library API documentation for the `Iterator`
106trait. Some of these methods call the `next` method in their definition, which
107is why you’re required to implement the `next` method when implementing the
108`Iterator` trait.
109
110Methods that call `next` are called *consuming adaptors*, because calling them
111uses up the iterator. One example is the `sum` method, which takes ownership of
112the iterator and iterates through the items by repeatedly calling `next`, thus
113consuming the iterator. As it iterates through, it adds each item to a running
114total and returns the total when iteration is complete. Listing 13-16 has a
115test illustrating a use of the `sum` method:
116
117<span class="filename">Filename: src/lib.rs</span>
118
fc512014 119```rust,noplayground
74b04a01 120{{#rustdoc_include ../listings/ch13-functional-features/listing-13-16/src/lib.rs:here}}
13cf67c4
XL
121```
122
123<span class="caption">Listing 13-16: Calling the `sum` method to get the total
124of all items in the iterator</span>
125
126We aren’t allowed to use `v1_iter` after the call to `sum` because `sum` takes
127ownership of the iterator we call it on.
128
129### Methods that Produce Other Iterators
130
131Other methods defined on the `Iterator` trait, known as *iterator adaptors*,
132allow you to change iterators into different kinds of iterators. You can chain
133multiple calls to iterator adaptors to perform complex actions in a readable
134way. But because all iterators are lazy, you have to call one of the consuming
135adaptor methods to get results from calls to iterator adaptors.
136
137Listing 13-17 shows an example of calling the iterator adaptor method `map`,
138which takes a closure to call on each item to produce a new iterator. The
139closure here creates a new iterator in which each item from the vector has been
140incremented by 1. However, this code produces a warning:
141
142<span class="filename">Filename: src/main.rs</span>
143
144```rust,not_desired_behavior
74b04a01 145{{#rustdoc_include ../listings/ch13-functional-features/listing-13-17/src/main.rs:here}}
13cf67c4
XL
146```
147
148<span class="caption">Listing 13-17: Calling the iterator adaptor `map` to
149create a new iterator</span>
150
151The warning we get is this:
152
f035d41b 153```console
74b04a01 154{{#include ../listings/ch13-functional-features/listing-13-17/output.txt}}
13cf67c4
XL
155```
156
157The code in Listing 13-17 doesn’t do anything; the closure we’ve specified
158never gets called. The warning reminds us why: iterator adaptors are lazy, and
159we need to consume the iterator here.
160
161To fix this and consume the iterator, we’ll use the `collect` method, which we
162used in Chapter 12 with `env::args` in Listing 12-1. This method consumes the
163iterator and collects the resulting values into a collection data type.
164
165In Listing 13-18, we collect the results of iterating over the iterator that’s
166returned from the call to `map` into a vector. This vector will end up
167containing each item from the original vector incremented by 1.
168
169<span class="filename">Filename: src/main.rs</span>
170
171```rust
74b04a01 172{{#rustdoc_include ../listings/ch13-functional-features/listing-13-18/src/main.rs:here}}
13cf67c4
XL
173```
174
175<span class="caption">Listing 13-18: Calling the `map` method to create a new
176iterator and then calling the `collect` method to consume the new iterator and
177create a vector</span>
178
179Because `map` takes a closure, we can specify any operation we want to perform
180on each item. This is a great example of how closures let you customize some
181behavior while reusing the iteration behavior that the `Iterator` trait
182provides.
183
184### Using Closures that Capture Their Environment
185
186Now that we’ve introduced iterators, we can demonstrate a common use of
187closures that capture their environment by using the `filter` iterator adaptor.
188The `filter` method on an iterator takes a closure that takes each item from
189the iterator and returns a Boolean. If the closure returns `true`, the value
190will be included in the iterator produced by `filter`. If the closure returns
191`false`, the value won’t be included in the resulting iterator.
192
193In Listing 13-19, we use `filter` with a closure that captures the `shoe_size`
194variable from its environment to iterate over a collection of `Shoe` struct
195instances. It will return only shoes that are the specified size.
196
197<span class="filename">Filename: src/lib.rs</span>
198
fc512014 199```rust,noplayground
74b04a01 200{{#rustdoc_include ../listings/ch13-functional-features/listing-13-19/src/lib.rs}}
13cf67c4
XL
201```
202
203<span class="caption">Listing 13-19: Using the `filter` method with a closure
204that captures `shoe_size`</span>
205
6a06907d 206The `shoes_in_size` function takes ownership of a vector of shoes and a shoe
13cf67c4
XL
207size as parameters. It returns a vector containing only shoes of the specified
208size.
209
6a06907d 210In the body of `shoes_in_size`, we call `into_iter` to create an iterator
13cf67c4
XL
211that takes ownership of the vector. Then we call `filter` to adapt that
212iterator into a new iterator that only contains elements for which the closure
213returns `true`.
214
215The closure captures the `shoe_size` parameter from the environment and
216compares the value with each shoe’s size, keeping only shoes of the size
217specified. Finally, calling `collect` gathers the values returned by the
218adapted iterator into a vector that’s returned by the function.
219
6a06907d 220The test shows that when we call `shoes_in_size`, we get back only shoes
13cf67c4
XL
221that have the same size as the value we specified.
222
223### Creating Our Own Iterators with the `Iterator` Trait
224
225We’ve shown that you can create an iterator by calling `iter`, `into_iter`, or
226`iter_mut` on a vector. You can create iterators from the other collection
227types in the standard library, such as hash map. You can also create iterators
228that do anything you want by implementing the `Iterator` trait on your own
229types. As previously mentioned, the only method you’re required to provide a
230definition for is the `next` method. Once you’ve done that, you can use all
231other methods that have default implementations provided by the `Iterator`
232trait!
233
234To demonstrate, let’s create an iterator that will only ever count from 1 to 5.
235First, we’ll create a struct to hold some values. Then we’ll make this struct
236into an iterator by implementing the `Iterator` trait and using the values in
237that implementation.
238
239Listing 13-20 has the definition of the `Counter` struct and an associated
240`new` function to create instances of `Counter`:
241
242<span class="filename">Filename: src/lib.rs</span>
243
fc512014 244```rust,noplayground
74b04a01 245{{#rustdoc_include ../listings/ch13-functional-features/listing-13-20/src/lib.rs}}
13cf67c4
XL
246```
247
248<span class="caption">Listing 13-20: Defining the `Counter` struct and a `new`
249function that creates instances of `Counter` with an initial value of 0 for
250`count`</span>
251
252The `Counter` struct has one field named `count`. This field holds a `u32`
253value that will keep track of where we are in the process of iterating from 1
254to 5. The `count` field is private because we want the implementation of
255`Counter` to manage its value. The `new` function enforces the behavior of
256always starting new instances with a value of 0 in the `count` field.
257
258Next, we’ll implement the `Iterator` trait for our `Counter` type by defining
259the body of the `next` method to specify what we want to happen when this
260iterator is used, as shown in Listing 13-21:
261
262<span class="filename">Filename: src/lib.rs</span>
263
fc512014 264```rust,noplayground
6a06907d 265{{#rustdoc_include ../listings/ch13-functional-features/listing-13-21/src/lib.rs:here}}
13cf67c4
XL
266```
267
268<span class="caption">Listing 13-21: Implementing the `Iterator` trait on our
269`Counter` struct</span>
270
271We set the associated `Item` type for our iterator to `u32`, meaning the
272iterator will return `u32` values. Again, don’t worry about associated types
273yet, we’ll cover them in Chapter 19.
274
275We want our iterator to add 1 to the current state, so we initialized `count`
74b04a01
XL
276to 0 so it would return 1 first. If the value of `count` is less than 5, `next`
277will increment `count` and return the current value wrapped in `Some`. Once
278`count` is 5, our iterator will stop incrementing `count` and always return
279`None`.
13cf67c4
XL
280
281#### Using Our `Counter` Iterator’s `next` Method
282
283Once we’ve implemented the `Iterator` trait, we have an iterator! Listing 13-22
284shows a test demonstrating that we can use the iterator functionality of our
285`Counter` struct by calling the `next` method on it directly, just as we did
286with the iterator created from a vector in Listing 13-15.
287
288<span class="filename">Filename: src/lib.rs</span>
289
fc512014 290```rust,noplayground
74b04a01 291{{#rustdoc_include ../listings/ch13-functional-features/listing-13-22/src/lib.rs:here}}
13cf67c4
XL
292```
293
294<span class="caption">Listing 13-22: Testing the functionality of the `next`
295method implementation</span>
296
297This test creates a new `Counter` instance in the `counter` variable and then
298calls `next` repeatedly, verifying that we have implemented the behavior we
299want this iterator to have: returning the values from 1 to 5.
300
301#### Using Other `Iterator` Trait Methods
302
303We implemented the `Iterator` trait by defining the `next` method, so we
304can now use any `Iterator` trait method’s default implementations as defined in
305the standard library, because they all use the `next` method’s functionality.
306
307For example, if for some reason we wanted to take the values produced by an
308instance of `Counter`, pair them with values produced by another `Counter`
309instance after skipping the first value, multiply each pair together, keep only
310those results that are divisible by 3, and add all the resulting values
311together, we could do so, as shown in the test in Listing 13-23:
312
313<span class="filename">Filename: src/lib.rs</span>
314
fc512014 315```rust,noplayground
74b04a01 316{{#rustdoc_include ../listings/ch13-functional-features/listing-13-23/src/lib.rs:here}}
13cf67c4
XL
317```
318
319<span class="caption">Listing 13-23: Using a variety of `Iterator` trait
320methods on our `Counter` iterator</span>
321
322Note that `zip` produces only four pairs; the theoretical fifth pair `(5,
323None)` is never produced because `zip` returns `None` when either of its input
324iterators return `None`.
325
326All of these method calls are possible because we specified how the `next`
327method works, and the standard library provides default implementations for
328other methods that call `next`.