]> git.proxmox.com Git - rustc.git/blame - src/doc/book/src/ch13-02-iterators.md
bump version to 1.80.1+dfsg1-1~bpo12+pve1
[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
04454e1e 10Listing 13-10 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
04454e1e 15{{#rustdoc_include ../listings/ch13-functional-features/listing-13-10/src/main.rs:here}}
13cf67c4
XL
16```
17
04454e1e 18<span class="caption">Listing 13-10: Creating an iterator</span>
13cf67c4 19
923072b8
FG
20The iterator is stored in the `v1_iter` variable. Once we’ve created an
21iterator, we can use it in a variety of ways. In Listing 3-5 in Chapter 3, we
22iterated over an array using a `for` loop to execute some code on each of its
23items. Under the hood this implicitly created and then consumed an iterator,
24but we glossed over how exactly that works until now.
13cf67c4 25
923072b8
FG
26In the example in Listing 13-11, we separate the creation of the iterator from
27the use of the iterator in the `for` loop. When the `for` loop is called using
28the iterator in `v1_iter`, each element in the iterator is used in one
29iteration of the loop, which prints out each value.
13cf67c4
XL
30
31```rust
04454e1e 32{{#rustdoc_include ../listings/ch13-functional-features/listing-13-11/src/main.rs:here}}
13cf67c4
XL
33```
34
04454e1e 35<span class="caption">Listing 13-11: Using an iterator in a `for` loop</span>
13cf67c4
XL
36
37In languages that don’t have iterators provided by their standard libraries,
38you would likely write this same functionality by starting a variable at index
390, using that variable to index into the vector to get a value, and
40incrementing the variable value in a loop until it reached the total number of
41items in the vector.
42
43Iterators handle all that logic for you, cutting down on repetitive code you
44could potentially mess up. Iterators give you more flexibility to use the same
45logic with many different kinds of sequences, not just data structures you can
46index into, like vectors. Let’s examine how iterators do that.
47
48### The `Iterator` Trait and the `next` Method
49
50All iterators implement a trait named `Iterator` that is defined in the
51standard library. The definition of the trait looks like this:
52
53```rust
9fa01778 54pub trait Iterator {
13cf67c4
XL
55 type Item;
56
57 fn next(&mut self) -> Option<Self::Item>;
58
59 // methods with default implementations elided
60}
61```
62
63Notice this definition uses some new syntax: `type Item` and `Self::Item`,
64which are defining an *associated type* with this trait. We’ll talk about
65associated types in depth in Chapter 19. For now, all you need to know is that
66this code says implementing the `Iterator` trait requires that you also define
67an `Item` type, and this `Item` type is used in the return type of the `next`
68method. In other words, the `Item` type will be the type returned from the
69iterator.
70
71The `Iterator` trait only requires implementors to define one method: the
72`next` method, which returns one item of the iterator at a time wrapped in
73`Some` and, when iteration is over, returns `None`.
74
04454e1e 75We can call the `next` method on iterators directly; Listing 13-12 demonstrates
13cf67c4 76what values are returned from repeated calls to `next` on the iterator created
9fa01778 77from the vector.
13cf67c4
XL
78
79<span class="filename">Filename: src/lib.rs</span>
80
fc512014 81```rust,noplayground
04454e1e 82{{#rustdoc_include ../listings/ch13-functional-features/listing-13-12/src/lib.rs:here}}
13cf67c4
XL
83```
84
04454e1e 85<span class="caption">Listing 13-12: Calling the `next` method on an
13cf67c4
XL
86iterator</span>
87
88Note that we needed to make `v1_iter` mutable: calling the `next` method on an
89iterator changes internal state that the iterator uses to keep track of where
90it is in the sequence. In other words, this code *consumes*, or uses up, the
91iterator. Each call to `next` eats up an item from the iterator. We didn’t need
92to make `v1_iter` mutable when we used a `for` loop because the loop took
93ownership of `v1_iter` and made it mutable behind the scenes.
94
95Also note that the values we get from the calls to `next` are immutable
96references to the values in the vector. The `iter` method produces an iterator
97over immutable references. If we want to create an iterator that takes
98ownership of `v1` and returns owned values, we can call `into_iter` instead of
99`iter`. Similarly, if we want to iterate over mutable references, we can call
100`iter_mut` instead of `iter`.
101
102### Methods that Consume the Iterator
103
104The `Iterator` trait has a number of different methods with default
105implementations provided by the standard library; you can find out about these
106methods by looking in the standard library API documentation for the `Iterator`
107trait. Some of these methods call the `next` method in their definition, which
108is why you’re required to implement the `next` method when implementing the
109`Iterator` trait.
110
111Methods that call `next` are called *consuming adaptors*, because calling them
112uses up the iterator. One example is the `sum` method, which takes ownership of
113the iterator and iterates through the items by repeatedly calling `next`, thus
114consuming the iterator. As it iterates through, it adds each item to a running
04454e1e 115total and returns the total when iteration is complete. Listing 13-13 has a
13cf67c4
XL
116test illustrating a use of the `sum` method:
117
118<span class="filename">Filename: src/lib.rs</span>
119
fc512014 120```rust,noplayground
04454e1e 121{{#rustdoc_include ../listings/ch13-functional-features/listing-13-13/src/lib.rs:here}}
13cf67c4
XL
122```
123
04454e1e 124<span class="caption">Listing 13-13: Calling the `sum` method to get the total
13cf67c4
XL
125of all items in the iterator</span>
126
127We aren’t allowed to use `v1_iter` after the call to `sum` because `sum` takes
128ownership of the iterator we call it on.
129
130### Methods that Produce Other Iterators
131
923072b8
FG
132*Iterator adaptors* are methods defined on the `Iterator` trait that don’t
133consume the iterator. Instead, they produce different iterators by changing
134some aspect of the original iterator.
13cf67c4 135
2b03887a 136Listing 13-14 shows an example of calling the iterator adaptor method `map`,
923072b8
FG
137which takes a closure to call on each item as the items are iterated through.
138The `map` method returns a new iterator that produces the modified items. The
139closure here creates a new iterator in which each item from the vector will be
140incremented by 1:
13cf67c4
XL
141
142<span class="filename">Filename: src/main.rs</span>
143
144```rust,not_desired_behavior
04454e1e 145{{#rustdoc_include ../listings/ch13-functional-features/listing-13-14/src/main.rs:here}}
13cf67c4
XL
146```
147
04454e1e 148<span class="caption">Listing 13-14: Calling the iterator adaptor `map` to
13cf67c4
XL
149create a new iterator</span>
150
923072b8 151However, this code produces a warning:
13cf67c4 152
f035d41b 153```console
04454e1e 154{{#include ../listings/ch13-functional-features/listing-13-14/output.txt}}
13cf67c4
XL
155```
156
04454e1e 157The code in Listing 13-14 doesn’t do anything; the closure we’ve specified
13cf67c4
XL
158never gets called. The warning reminds us why: iterator adaptors are lazy, and
159we need to consume the iterator here.
160
923072b8
FG
161To fix this warning and consume the iterator, we’ll use the `collect` method,
162which we used in Chapter 12 with `env::args` in Listing 12-1. This method
163consumes the iterator and collects the resulting values into a collection data
164type.
13cf67c4 165
04454e1e 166In Listing 13-15, we collect the results of iterating over the iterator that’s
13cf67c4
XL
167returned from the call to `map` into a vector. This vector will end up
168containing each item from the original vector incremented by 1.
169
170<span class="filename">Filename: src/main.rs</span>
171
172```rust
04454e1e 173{{#rustdoc_include ../listings/ch13-functional-features/listing-13-15/src/main.rs:here}}
13cf67c4
XL
174```
175
04454e1e 176<span class="caption">Listing 13-15: Calling the `map` method to create a new
13cf67c4
XL
177iterator and then calling the `collect` method to consume the new iterator and
178create a vector</span>
179
180Because `map` takes a closure, we can specify any operation we want to perform
181on each item. This is a great example of how closures let you customize some
182behavior while reusing the iteration behavior that the `Iterator` trait
183provides.
184
923072b8
FG
185You can chain multiple calls to iterator adaptors to perform complex actions in
186a readable way. But because all iterators are lazy, you have to call one of the
187consuming adaptor methods to get results from calls to iterator adaptors.
188
13cf67c4
XL
189### Using Closures that Capture Their Environment
190
923072b8
FG
191Many iterator adapters take closures as arguments, and commonly the closures
192we’ll specify as arguments to iterator adapters will be closures that capture
064997fb
FG
193their environment.
194
195For this example, we’ll use the `filter` method that takes a closure. The
196closure gets an item from the iterator and returns a `bool`. If the closure
197returns `true`, the value will be included in the iteration produced by
198`filter`. If the closure returns `false`, the value won’t be included.
13cf67c4 199
04454e1e 200In Listing 13-16, we use `filter` with a closure that captures the `shoe_size`
13cf67c4
XL
201variable from its environment to iterate over a collection of `Shoe` struct
202instances. It will return only shoes that are the specified size.
203
204<span class="filename">Filename: src/lib.rs</span>
205
fc512014 206```rust,noplayground
04454e1e 207{{#rustdoc_include ../listings/ch13-functional-features/listing-13-16/src/lib.rs}}
13cf67c4
XL
208```
209
04454e1e 210<span class="caption">Listing 13-16: Using the `filter` method with a closure
13cf67c4
XL
211that captures `shoe_size`</span>
212
6a06907d 213The `shoes_in_size` function takes ownership of a vector of shoes and a shoe
13cf67c4
XL
214size as parameters. It returns a vector containing only shoes of the specified
215size.
216
6a06907d 217In the body of `shoes_in_size`, we call `into_iter` to create an iterator
13cf67c4
XL
218that takes ownership of the vector. Then we call `filter` to adapt that
219iterator into a new iterator that only contains elements for which the closure
220returns `true`.
221
222The closure captures the `shoe_size` parameter from the environment and
223compares the value with each shoe’s size, keeping only shoes of the size
224specified. Finally, calling `collect` gathers the values returned by the
225adapted iterator into a vector that’s returned by the function.
226
6a06907d 227The test shows that when we call `shoes_in_size`, we get back only shoes
13cf67c4 228that have the same size as the value we specified.