]>
Commit | Line | Data |
---|---|---|
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 | |
4 | we use it with --- I think this is an important point to make early, I did find | |
5 | it difficult to know what an iterator actually was throughout, and how it | |
6 | depends 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 | |
8 | like an item that's used in iteration rather than something that performs the | |
9 | process of iteration itself, is that right? Like a counter passed from element | |
10 | to 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 | ||
13 | The iterator pattern allows you to perform some task on a sequence of items in | |
14 | turn. An *iterator* is responsible for the logic around iterating over each item | |
15 | in the sequence and determining when the sequence has finished. When we use | |
16 | iterators, we don't have to reimplement that logic ourselves. | |
17 | ||
18 | In Rust, iterators are *lazy*, which means they have no effect until we call | |
19 | methods on them that consume the iterator to use it up. For example, the code | |
20 | in Listing 13-13 creates an iterator over the items in the vector `v1` by | |
21 | calling the `iter` method defined on `Vec`. This code by itself doesn't do | |
22 | anything useful: | |
cc61c64b | 23 | |
7cac9316 XL |
24 | ```rust |
25 | let v1 = vec![1, 2, 3]; | |
26 | ||
27 | let v1_iter = v1.iter(); | |
28 | ``` | |
29 | ||
30 | <span class="caption">Listing 13-13: Creating an iterator; this by itself isn't | |
31 | useful</span> | |
32 | ||
33 | After creating an iterator, we can choose to use it in a variety of ways. In | |
34 | Listing 3-6, we actually used iterators with `for` loops to execute some code | |
35 | on each item, though we glossed over what the call to `iter` did until now. The | |
36 | example in Listing 13-14 separates the creation of the iterator from the use of | |
37 | the iterator in the `for` loop. The iterator is stored in the `v1_iter` | |
38 | variable, and no iteration takes place at that time. Once the `for` loop is | |
39 | called using the iterator in `v1_iter`, then each element in the iterator is | |
40 | used in one iteration of the loop, which prints out each value: | |
cc61c64b XL |
41 | |
42 | ```rust | |
43 | let v1 = vec![1, 2, 3]; | |
44 | ||
7cac9316 | 45 | let v1_iter = v1.iter(); |
cc61c64b | 46 | |
7cac9316 XL |
47 | for 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` |
53 | loop</span> | |
cc61c64b | 54 | |
7cac9316 XL |
55 | In languages that don't have iterators provided by their standard libraries, we |
56 | would likely write this same functionality by starting a variable at index 0, | |
57 | using that variable to index into the vector to get a value, and incrementing | |
58 | the variable value in a loop until its value gets up to the total number of | |
59 | items in the vector. Iterators take care of all of that logic for us, which | |
60 | cuts down on the repetitive code we would have to write and potentially mess up. | |
61 | In addition, the way iterators are implemented gives us more flexibility to | |
62 | use the same logic with many different kinds of sequences, not just data | |
63 | structures that we can index into like vectors. Let's see how iterators do that. | |
64 | ||
65 | ### The `Iterator` trait and the `next` method | |
66 | ||
67 | Iterators all implement a trait named `Iterator` that is defined in the | |
68 | standard library. The definition of the trait looks like this: | |
69 | ||
70 | ```rust | |
71 | trait 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 |
80 | You'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 | |
82 | talk about associated types in depth in Chapter 19, but for now, all you need | |
83 | to know is that this code says implementing `Iterator` trait requires that you | |
84 | also define an `Item` type, and this `Item` type is used in the return type of | |
85 | the `next` method. In other words, the `Item` type will be the type of element | |
86 | that's returned from the iterator. | |
87 | ||
88 | The `next` method is the only method that the `Iterator` trait requires | |
89 | implementers of the trait to define. `next` returns one item of the iterator | |
90 | at a time wrapped in `Some`, and when iteration is over, it returns `None`. | |
91 | We can call the `next` method on iterators directly if we'd like; Listing 13-14 | |
92 | has a test that demonstrates the values we'd get on repeated calls to `next` | |
93 | on the iterator created from the vector: | |
94 | ||
95 | <span class="filename">Filename: src/lib.rs</span> | |
96 | ||
97 | ```rust,test_harness | |
98 | #[test] | |
99 | fn 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 | |
112 | iterator</span> | |
113 | ||
114 | Note that we needed to make `v1_iter` mutable: calling the `next` method on an | |
115 | iterator changes the iterator's state that keeps track of where it is in the | |
116 | sequence. Put another way, this code *consumes*, or uses up, the iterator. Each | |
117 | call to `next` eats up an item from the iterator. | |
118 | ||
119 | Also note that the values we get from the calls to `next` are immutable | |
120 | references to the values in the vector. The `iter` method produces an iterator | |
121 | over immutable references. If we wanted to create an iterator that takes | |
122 | ownership 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 | |
129 | doesn't look like we do in this section, I think that's important to lay that | |
130 | out clearly --> | |
131 | <!-- This next paragraph doesn't give much away to me I'm afraid, not being | |
132 | clear what we mean by *consume* at this point. Is a consuming adaptor like a | |
133 | catalyst? --> | |
134 | <!-- I hope this section addresses these comments you had /Carol --> | |
135 | ||
136 | The `Iterator` trait has a number of different methods with default | |
137 | implementations provided for us by the standard library; you can find out all | |
138 | about these methods by looking in the standard library API documentation for | |
139 | the `Iterator` trait. Some of these methods call the `next` method in their | |
140 | definition, which is why we're required to implement the `next` method when | |
141 | implementing the `Iterator` trait. | |
142 | ||
143 | <!-- Is there somewhere they can learn about all the methods and what they do, | |
144 | how to use them? This seems like a good sample example, and if we can broaden | |
145 | it out that would be really helpful --> | |
146 | <!-- I've moved this comment here since you made this comment on the last | |
147 | version of this chapter right after a spot where we mentioned looking at the | |
148 | standard library API documentation for the iterator trait, like we're now doing | |
149 | in the above paragraph. That's where the reader should go to learn about | |
150 | all the methods and what they do and how to use them. Can you elaborate on why | |
151 | that wasn't clear in the previous version of the chapter? Is there a reason why | |
152 | the standard library API documentation didn't sound like that place to go? | |
153 | /Carol --> | |
154 | ||
155 | The methods that call the `next` method are called *consuming adaptors*, since | |
156 | calling 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 | |
158 | the items by repeatedly calling `next`, thus consuming the iterator. As it | |
159 | iterates through each item, it adds each item to a running total and returns | |
160 | the total when iteration has completed. Listing 13-15 has a test illustrating a | |
161 | use of the `sum` method: | |
162 | ||
163 | <span class="filename">Filename: src/lib.rs</span> | |
164 | ||
165 | ```rust | |
166 | #[test] | |
167 | fn 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 | |
179 | of all items in the iterator</span> | |
cc61c64b | 180 | |
7cac9316 XL |
181 | We aren't allowed to use `v1_iter` after the call to `sum` since `sum` takes |
182 | ownership of the iterator we call it on. | |
cc61c64b | 183 | |
7cac9316 | 184 | ### Methods in the `Iterator` Trait that Produce Other Iterators |
cc61c64b | 185 | |
7cac9316 XL |
186 | Another kind of method defined on the `Iterator` trait are methods that produce |
187 | other iterators. These methods are called *iterator adaptors* and allow us to | |
188 | change iterators into different kind of iterators. We can chain multiple calls | |
189 | to iterator adaptors. Because all iterators are lazy, however, we have to | |
190 | call one of the consuming adaptor methods in order to get results from calls | |
191 | to iterator adaptors. Listing 13-16 shows an example of calling the iterator | |
192 | adaptor method `map`, which takes a closure that `map` will call on each | |
193 | item in order to produce a new iterator in which each item from the vector has | |
194 | been incremented by 1. This code produces a warning, though: | |
195 | ||
196 | <span class="filename">Filename: src/main.rs</span> | |
cc61c64b XL |
197 | |
198 | ```rust | |
199 | let v1: Vec<i32> = vec![1, 2, 3]; | |
200 | ||
7cac9316 | 201 | v1.iter().map(|x| x + 1); |
cc61c64b XL |
202 | ``` |
203 | ||
7cac9316 XL |
204 | <span class="caption">Listing 13-16: Calling the iterator adapter `map` to |
205 | create a new iterator</span> | |
206 | ||
207 | The warning we get is: | |
cc61c64b XL |
208 | |
209 | ```text | |
210 | warning: unused result which must be used: iterator adaptors are lazy and do | |
7cac9316 | 211 | nothing unless consumed |
cc61c64b XL |
212 | --> src/main.rs:4:1 |
213 | | | |
7cac9316 | 214 | 4 | 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 |
220 | The code in Listing 13-16 isn't actually doing anything; the closure we've |
221 | specified never gets called. The warning reminds us why: iterator adaptors are | |
222 | lazy, and we probably meant to consume the iterator here. | |
cc61c64b | 223 | |
7cac9316 XL |
224 | In order to fix this warning and consume the iterator to get a useful result, |
225 | we're going to use the `collect` method, which we saw briefly in Chapter 12. | |
226 | This method consumes the iterator and collects the resulting values into a | |
227 | data structure. In Listing 13-17, we're going to collect the results of | |
228 | iterating over the iterator returned from the call to `map` into a vector that | |
229 | will 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 | 234 | let v1: Vec<i32> = vec![1, 2, 3]; |
cc61c64b | 235 | |
7cac9316 XL |
236 | let v2: Vec<_> = v1.iter().map(|x| x + 1).collect(); |
237 | ||
238 | assert_eq!(v2, vec![2, 3, 4]); | |
239 | ``` | |
240 | ||
241 | <span class="caption">Listing 13-17: Calling the `map` method to create a new | |
242 | iterator, then calling the `collect` method to consume the new iterator and | |
243 | create a vector</span> | |
244 | ||
245 | Because `map` takes a closure, we can specify any operation that we want to | |
246 | perform on each item that we iterate over. This is a great example of how using | |
247 | closures lets us customize some behavior while reusing the iteration behavior | |
248 | that the `Iterator` trait provides. | |
249 | ||
250 | <!-- I'm not clear from this last sentence which part is iterating through each | |
251 | element, iter or map? What is map actually doing?--> | |
252 | <!--Ah, I'm afraid I completely failed to follow this. What is the second | |
253 | iterator for? I'm still not clear on what map does, can you expand on this? It | |
254 | seems crucial to using iterators. Map applies the iterator to each element, | |
255 | which applies the closure? | |
256 | ||
257 | Also, 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 | |
260 | had on the last version of this chapter about the difference between | |
261 | iter and map. I hope the added examples where we've used iter without map have | |
262 | cleared up the last question. /Carol --> | |
263 | ||
264 | ### Using Closures that Capture their Environment with Iterators | |
265 | ||
266 | Now that we've introduced iterators, we can demonstrate a common use of | |
267 | closures that capture their environment by using the `filter` iterator adapter. | |
268 | The `filter` method on an iterator takes a closure that takes each item from | |
269 | the iterator and returns a boolean. If the closure returns `true`, the value | |
270 | will 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 | |
272 | demonstrates using `filter` with a closure that captures the `shoe_size` | |
273 | variable from its environment in order to iterate over a collection of `Shoe` | |
274 | struct 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)] | |
280 | struct Shoe { | |
281 | size: i32, | |
282 | style: String, | |
283 | } | |
284 | ||
285 | fn 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] | |
292 | fn 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 |
312 | that captures `shoe_size`</span> | |
313 | ||
314 | <!-- Will add wingdings in libreoffice /Carol --> | |
315 | ||
316 | The `shoes_in_my_size` function takes ownership of a vector of shoes and a shoe | |
317 | size as parameters. It returns a vector containing only shoes of the specified | |
318 | size. In the body of `shoes_in_my_size`, we call `into_iter` to create an | |
319 | iterator that takes ownership of the vector. Then we call `filter` to adapt | |
320 | that iterator into a new iterator that only contains elements for which the | |
321 | closure returns `true`. The closure we've specified captures the `shoe_size` | |
322 | parameter from the environment and uses the value to compare with each shoe's | |
323 | size 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 | |
325 | that the function returns. | |
326 | ||
327 | The test shows that when we call `shoes_in_my_size`, we only get back shoes | |
328 | that 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 | |
333 | that right? I assumed the whole thing we were making was an iterator at first, | |
334 | which 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 | |
336 | is to you between "a program with an iterator inside" and "whole thing we were | |
337 | making was an iterator"? I don't understand what you mean by these terms so I'm | |
338 | not sure how to clear this up. /Carol --> | |
339 | ||
340 | We'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 | |
342 | types in the standard library, such as hash map. Additionally, we can implement | |
343 | the `Iterator` trait in order to create iterators that do anything we want. | |
344 | As previously mentioned, the only method we're required to provide a definition | |
345 | for is the `next` method. Once we've done that, we can use all the other | |
346 | methods that have default implementations provided by the `Iterator` trait on | |
347 | our iterator! | |
348 | ||
349 | <!-- NEXT PARAGRAPH WRAPPED WEIRD INTENTIONALLY SEE #199 --> | |
350 | ||
351 | The iterator we're going to create is one that will only ever count from 1 | |
352 | to 5. First, we'll create a struct to hold on to some values, and then we'll | |
353 | make this struct into an iterator by implementing the `Iterator` trait and use | |
354 | the values in that implementation. | |
355 | ||
356 | Listing 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 | |
362 | struct Counter { | |
363 | count: u32, | |
364 | } | |
365 | ||
366 | impl 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` |
374 | function 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 | |
378 | track of what they're working on. Can you also just sum up in a line what this | |
379 | code has accomplished so far? I moved this down from above the code, if this | |
380 | will do? --> | |
381 | <!-- Done /Carol --> | |
382 | ||
383 | The `Counter` struct has one field named `count`. This field holds a `u32` | |
384 | value that will keep track of where we are in the process of iterating from 1 | |
385 | to 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 | |
387 | of 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 | |
390 | next line is telling us? --> | |
391 | <!-- So does this code just initialize it with 0? Is that jat { count: 0 } | |
392 | does?--> | |
393 | <!-- I've rearranged to make this clearer /Carol --> | |
394 | ||
cc61c64b | 395 | Next, we're going to implement the `Iterator` trait for our `Counter` type by |
7cac9316 XL |
396 | defining the body of the `next` method to specify what we want to happen when |
397 | this 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 | # | |
406 | impl 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 |
426 | We set the associated `Item` type for our iterator to `u32`, meaning the |
427 | iterator will return `u32` values. Again, don't worry about associated types | |
428 | yet, we'll be covering them in Chapter 19. We want our iterator to add one to | |
429 | the current state, which is why we initialized `count` to 0: we want our | |
430 | iterator to return one first. If the value of `count` is less than six, `next` | |
431 | will return the current value wrapped in `Some`, but if `count` is six or | |
432 | higher, our iterator will return `None`. | |
cc61c64b | 433 | |
7cac9316 | 434 | #### Using Our `Counter` Iterator's `next` Method |
cc61c64b | 435 | |
7cac9316 XL |
436 | Once we've implemented the `Iterator` trait, we have an iterator! Listing 13-21 |
437 | shows 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 | |
439 | we 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] | |
463 | fn 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` |
476 | method implementation</span> | |
477 | ||
478 | This test creates a new `Counter` instance in the `counter` variable and then | |
479 | calls `next` repeatedly, verifying that we have implemented the behavior we | |
480 | want 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 | |
483 | counter, and the rest of them merely call counter with next, store it in x, and | |
484 | then print x? And we have to do that 5 times to get the 1-5 count? Phew, could | |
485 | you 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 | |
487 | I 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 | ||
492 | Because we implemented the `Iterator` trait by defining the `next` method, we | |
493 | can now use any `Iterator` trait method's default implementations that the | |
494 | standard library has defined, since they all use the `next` method's | |
495 | functionality. | |
496 | ||
497 | <!-- So we can't just use these methods anyway? It seems like we did earlier, | |
498 | but 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 | |
500 | have to *define* `next` before we can use the other methods. I hope the various | |
501 | rewordings and reworkings have made this clearer by this point. /Carol --> | |
502 | ||
503 | <!-- below: once you've done what, defined a default implementation? Only then | |
504 | can you use other adapters, is that what we're saying? And I'm still not clear | |
505 | on what an adapter does/means, as opposed to a method, or consumer, at this | |
506 | point. --> | |
507 | <!-- I hope this comment has been cleared up too /Carol --> | |
508 | ||
509 | For example, if for some reason we wanted to take the values that an instance | |
510 | of `Counter` produces, pair those values with values produced by another | |
511 | `Counter` instance after skipping the first value that instance produces, | |
512 | multiply each pair together, keep only those results that are divisible by | |
513 | three, and add all the resulting values together, we could do so as shown in | |
514 | the 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] | |
547 | fn 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 |
557 | methods on our `Counter` iterator</span> | |
558 | ||
cc61c64b XL |
559 | Note that `zip` produces only four pairs; the theoretical fifth pair `(5, |
560 | None)` is never produced because `zip` returns `None` when either of its input | |
561 | iterators return `None`. | |
562 | ||
563 | All of these method calls are possible because we implemented the `Iterator` | |
7cac9316 XL |
564 | trait by specifying how the `next` method works and the standard library |
565 | provides default implementations for other methods that call `next`. |