# Processing a Series of Items with Iterators Iterator patterns allow you to perform some task on a sequence of items in turn. An iterator is responsibl for the logic of iterating over each item and determining when the sequence has finished. When you use iterators, you don't have to reimplement that logic yourself again. Rust's iterators are *lasy*, meaning they have no effect until yo call methods that consume the iterator to use it up In this example the code creates an iterator over the items in the vecotr `v1` by calling the `iter` method defined on `Vec` This code does nothing useful. ```rust let v1 = vec![1, 2, 3]; let v1_iter = v1.iter(); ``` The iterator is stored in the `v1_iter` variable. Once an iterator is created, we can use it in a variety of ways. Before we iterator over an array using a `for` loop to execute some code on each of its items. Under the hood this implicitly created and then consumed an iterator, but we glossed over how exactly that works until now. In this example, we separate the creation of the iterator from the use of the iterator in the `for` loop. When the `for` loop is called using th iterator in `v1_iter`, each element in the iterator is used in one iteration of the loop which prints out each value. ```rust let v1 = vec![1, 2, 3]; let v1_iter = v1.iter(); for val in v1_iter { println!("Got: {val}"); } ``` In languages that don't have iterators provided by their std libraries, you would likely wirte this same functionality by starting at index 0. Using that variable to index into th vector to get a value and incrememting the variable in a loop until it reached the total number of items in the vector. Iterators handle all that logic for you, removing repetitive code that you could mess up. Iterators gives mroe flexibility to use the same logic with many different kinds of sequences, not just data structs you can index into (vectors for example). ## The `Iterator` Trait and the `next` Method All iterators implement a trait named `Iterator` that is defined in the std library The defintion of the `Iterator` trait looks like this: ```rust pub trait Iterator { type Item; fn next(&mut self) -> Option; // methods with default implementations elided } ``` Note this definition uses some new syntax, `type Item` and `Self::Item`, which are defining an *associated type* with this trait Associated types will be discussed in ch20 (Advanced Features) For now know that this code says implementing the `Iterator` trait requires you also defined an `Item` type. This `Item` type is usd in the return in the return type of the `next` method. The `Item` tpye ill be the type returned form the iterator. The `Iterator` trait only requires implmentors to define one method; `next` method which returns one item of the iterator at a time wrapped in `Some` and when the iteration is over, returns `None`. We can call the `next` method on iterators directly This example demonstrates what values are returned from repeated calls to `next` on the iterator created from the vector. ```rust #[test] fn iterator_demonstration() { let v1 = vec![1, 2, 3]; let mut v1_iter = v1.iter(); assert_eq!(v1_iter.next(), Some(&1)); assert_eq!(v1_iter.next(), Some(&2)); assert_eq!(v1_iter.next(), Some(&3)); assert_eq!(v1_iter.next(), None); } ``` Notice that we need to make `v1_iter` mutable. Calling the `next` method on an iterator changes internal state that the iterator uses to keep track of where it is in the sequence. It could also be said that the code *consumes*, or uses up, the iterator. Each call to `next` comsumes an item form the iterator. We didn't need to make `v1_iter` mutable when we used a `for` loop because the loop took ownership of `v1_iter` and made it mutable under the hood. Note as well the values that we get from the `next` are immutable reference to the values in the vector. The `iter` mthod produces an iterator over immutable references. If we want to create an iterator that takes ownership of `v1` and returns owned values, we can call `into_iter`. If you want to iterate over mutalbe references, you can call `iter_mut` ## Methods that Consume the Iterator The `Iterator` trait has a number of different methods with default implementations provided by the std library. You can find out about these by looking the std library API documentation for the `Iterator` trait. Some these methods call the `next` method in their definition, which is why you are required to implement the `Iterator` trait. Methods that call `next` are called *consuming adapters*, becaise calling them uses up the iterator. One example is the `sum` metod which takes ownership of the iterator and iterates through the items by repeatedly calling `next` thus consuming the iterator. As it iterates through it adds each item to a running total, this comsumes the iterator. When it is complete it return the total Here is a test illustrating a use of the `sum` method ```rust #[test] fn iterator_sum() { let v1 = vec![1, 2, 3]; let v1_iter = v1.iter(); let total: i32 = v1_iter.sum(); assert_eq!(total, 6); } ``` We aren't allowed to use `v1_iter` after the call to `sum because it takes ownership of the iterator we call it on. ## Methods that Produce Other Iterators *Iterator adapters* are methods defined on the `Iterator` trait that don't consume the iterator. Instead, they produce different iterators by changing some aspect of the original iterator. This example shows calling an iterator adapter method `map`, which takes a closure to call on each item as the items are iterated through. The `map` method returns a new iterator that produces the modified items. The closure here creates a new iterator in which each item from the vector will be incremeted by 1 ```rust let v1: Vec = vec![1, 2, 3]; v1.iter().map(|x| x + 1); ``` But this code produces a warning ``` $ cargo run Compiling iterators v0.1.0 (file:///projects/iterators) warning: unused `Map` that must be used --> src/main.rs:4:5 | 4 | v1.iter().map(|x| x + 1); | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: iterators are lazy and do nothing unless consumed = note: `#[warn(unused_must_use)]` on by default help: use `let _ = ...` to ignore the resulting value | 4 | let _ = v1.iter().map(|x| x + 1); | +++++++ warning: `iterators` (bin "iterators") generated 1 warning Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.47s Running `target/debug/iterators` ``` This doesnt do anything. The closure we sepcified never gets called. The warning reminds us why: iterator adapters are lazy and we need to consume the iterator here. To fix this warning and consume the iterator, we will use the `collect` method, which we used in Ch 12 with `env::args`. This method consumes the iterator and collects the resulting values into a collection data type. In this next example we collect the results of the iterating over the iterator that is returned form the call to `map` into a vector. This vector will end up containing each item form the original vector incremeted by 1. ```rust let v1: Vec = vec![1, 2, 3]; let v2: Vec<_> = v1.iter().map(|x| x + 1).collect(); assert_eq!(v2, vec![2, 3, 4]); ``` Because `map` takes a closure, we can specify any operation we want to perform on each item. This is a good eample of how closures let you do custome behavior while reusing the iteration behavior that the `Iterator` trait provides. You can chain mutliple calls to iterator adapters to perform compex action is a readable way. Due to all iterators being lasy, you have to call one of the consuming adapter methods to get results ffrom calls to iterator adapters. ## Using Closures that Capture Their Environment Many iterator adapters take closures as args and commonly the closures we will specify as ags to iterator adapters will be closures that capture their environment. In this example we use the `filter` method that takes a closure. The closure get an item form the iterator and returns a `bool` If the closure returns `true`, the value will be included in the iteration produced by `filter`. If the closure returns `false`, the value won't be included. Here we use `filer` with a closure that captures the `shoe_size` variable from its environment to iterate over a collection of `Shoe` struct instances. It will return only shoes that are the specified size. ```rust #[derive(PartialEq, Debug)] struct Shoe { size: u32, style: String, } fn shoes_in_size(shoes: Vec, shoe_size: u32) -> Vec { shoes.into_iter().filter(|s| s.size == shoe_size).collect() } #[cfg(test)] mod tests { use super::*; #[test] fn filters_by_size() { let shoes = vec![ Shoe { size: 10, style: String::from("sneaker"), }, Shoe { size: 13, style: String::from("sandal"), }, Shoe { size: 10, style: String::from("boot"), }, ]; let in_my_size = shoes_in_size(shoes, 10); assert_eq!( in_my_size, vec![ Shoe { size: 10, style: String::from("sneaker") }, Shoe { size: 10, style: String::from("boot") }, ] ); } } ``` The `shoes_in_size` function takes ownership of a vector of shoes and a shoe size parameters. It returns a vector containing only shoes of the specified size. In the body of `shoes_in_size` we call `into_iter` to create an iterator that takes ownership of the vector. We then call `filter` to adapt that iterator into a new iterator that only contains elements for which the closure returns `true`. The closure captures the `shoe_size` parameter from the environment and compares the value with each shoe's size, keeping only shoes of the size specified. Calling `collect` finally gathers the values returned by the adapted iterator into a vector that is returned by the function. This test shows that when we call `shoes_in_size`, we get back only shoes that have the same size as te value specified.