diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 6e4456e4..47e81978 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -171,9 +171,11 @@
- [Welcome](welcome-day-4.md)
- [Iterators](iterators.md)
- - [`Iterator`](iterators/iterator.md)
- - [`IntoIterator`](iterators/intoiterator.md)
+ - [Motivation](iterators/motivation.md)
+ - [`Iterator` Trait](iterators/iterator.md)
+ - [`Iterator` Helper Methods](iterators/helpers.md)
- [`collect`](iterators/collect.md)
+ - [`IntoIterator`](iterators/intoiterator.md)
- [Exercise: Iterator Method Chaining](iterators/exercise.md)
- [Solution](iterators/solution.md)
- [Modules](modules.md)
diff --git a/src/iterators/helpers.md b/src/iterators/helpers.md
new file mode 100644
index 00000000..5ea5f4c2
--- /dev/null
+++ b/src/iterators/helpers.md
@@ -0,0 +1,42 @@
+---
+minutes: 5
+---
+
+# `Iterator` Helper Methods
+
+In addition to the `next` method that defines how an iterator behaves, the
+`Iterator` trait provides 70+ helper methods that can be used to build
+customized iterators.
+
+```rust,editable
+let result: i32 = (1..=10) // Create a range from 1 to 10
+ .filter(|&x| x % 2 == 0) // Keep only even numbers
+ .map(|x| x * x) // Square each number
+ .sum(); // Sum up all the squared numbers
+
+println!("The sum of squares of even numbers from 1 to 10 is: {}", result);
+```
+
+
+
+- The `Iterator` trait implements many common functional programming operations
+ over collections (e.g. `map`, `filter`, `reduce`, etc). This is the trait
+ where you can find all the documentation about them.
+
+- Many of these helper methods take the original iterator and produce a new
+ iterator with different behavior. These are know as "iterator adapter
+ methods".
+
+- Some methods, like `sum` and `count`, consume the iterator and pull all of the
+ elements out of it.
+
+- These methods are designed to be chained together so that it's easy to build a
+ custom iterator that does exactly what you need.
+
+## More to Explore
+
+- Rust's iterators are extremely efficient and highly optimizable. Even complex
+ iterators made by combining many adapter methods will still result in code as
+ efficient as equivalent imperative implementations.
+
+
diff --git a/src/iterators/intoiterator.md b/src/iterators/intoiterator.md
index aeb22c24..631ca0bd 100644
--- a/src/iterators/intoiterator.md
+++ b/src/iterators/intoiterator.md
@@ -57,6 +57,11 @@ fn main() {
+- `IntoIterator` is the trait that makes for loops work. It is implemented by
+ collection types such as `Vec` and references to them such as `&Vec` and
+ `&[T]`. Ranges also implement it. This is why you can iterate over a vector
+ with `for i in some_vec { .. }` but `some_vec.next()` doesn't exist.
+
Click through to the docs for `IntoIterator`. Every implementation of
`IntoIterator` must declare two types:
diff --git a/src/iterators/iterator.md b/src/iterators/iterator.md
index d0b7c072..0d370794 100644
--- a/src/iterators/iterator.md
+++ b/src/iterators/iterator.md
@@ -2,49 +2,67 @@
minutes: 5
---
-# `Iterator`
+# `Iterator` Trait
-The [`Iterator`][1] trait supports iterating over values in a collection. It
-requires a `next` method and provides lots of methods. Many standard library
-types implement `Iterator`, and you can implement it yourself, too:
+The [`Iterator`][1] trait defines how an object can be used to produce a
+sequence of values. For example, if we wanted to create an iterator that can
+produce the elements of a slice it might look something like this:
```rust,editable
-struct Fibonacci {
- curr: u32,
- next: u32,
+struct SliceIter<'s> {
+ slice: &'s [i32],
+ i: usize,
}
-impl Iterator for Fibonacci {
- type Item = u32;
+impl<'s> Iterator for SliceIter<'s> {
+ type Item = &'s i32;
fn next(&mut self) -> Option {
- let new_next = self.curr + self.next;
- self.curr = self.next;
- self.next = new_next;
- Some(self.curr)
+ if self.i == self.slice.len() {
+ None
+ } else {
+ let next = &self.slice[self.i];
+ self.i += 1;
+ Some(next)
+ }
}
}
fn main() {
- let fib = Fibonacci { curr: 0, next: 1 };
- for (i, n) in fib.enumerate().take(5) {
- println!("fib({i}): {n}");
+ let slice = [2, 4, 6, 8].as_slice();
+ let iter = SliceIter { slice, i: 0 };
+ for elem in iter {
+ println!("elem: {elem}");
}
}
```
-- The `Iterator` trait implements many common functional programming operations
- over collections (e.g. `map`, `filter`, `reduce`, etc). This is the trait
- where you can find all the documentation about them. In Rust these functions
- should produce the code as efficient as equivalent imperative implementations.
+- The `SliceIter` example implements the same logic as the C-style `for` loop
+ demonstrated on the last slide.
-- `IntoIterator` is the trait that makes for loops work. It is implemented by
- collection types such as `Vec` and references to them such as `&Vec` and
- `&[T]`. Ranges also implement it. This is why you can iterate over a vector
- with `for i in some_vec { .. }` but `some_vec.next()` doesn't exist.
+- Point out to the students that iterators are lazy: Creating the iterator just
+ initializes the struct but does not otherwise do any work. No work happens
+ until the `next` method is called.
+
+- Iterators don't need to be finite! It's entirely valid to have an iterator
+ that will produce values forever. For example, a half open range like `0..`
+ will keep going until integer overflow occurs.
+
+## More to Explore
+
+- The "real" version of `SliceIter` is the [`slice::Iter`][2] type in the
+ standard library, however the real version uses pointers under the hood
+ instead of an index in order to eliminate bounds checks.
+
+- The `SliceIter` example is a good example of a struct that contains a
+ reference and therefore uses lifetime annotations.
+
+- You can also demonstrate adding a generic parameter to `SliceIter` to allow it
+ to work with any kind of slice (not just `&[i32]`).
[1]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
+[2]: https://doc.rust-lang.org/stable/std/slice/struct.Iter.html
diff --git a/src/iterators/motivation.md b/src/iterators/motivation.md
new file mode 100644
index 00000000..812dca8b
--- /dev/null
+++ b/src/iterators/motivation.md
@@ -0,0 +1,59 @@
+---
+minutes: 3
+---
+
+# Motivating Iterators
+
+If you want to iterate over the contents of an array, you'll need to define:
+
+- Some state to keep track of where you are in the iteration process, e.g. an
+ index.
+- A condition to determine when iteration is done.
+- Logic for updating the state of iteration each loop.
+- Logic for fetching each element using that iteration state.
+
+In a C-style for loop you declare these things directly:
+
+```c,editable
+for (int i = 0; i < array_len; i += 1) {
+ int elem = array[i];
+}
+```
+
+In Rust we bundle this state and logic together into an object known as an
+"iterator".
+
+
+
+- This slide provides context for what Rust iterators do under the hood. We use
+ the (hopefully) familiar construct of a C-style `for` loop to show how
+ iteration requires some state and some logic, that way on the next slide we
+ can show how an iterator bundles these together.
+
+- Rust doesn't have a C-style `for` loop, but we can express the same thing with
+ `while`:
+ ```rust,editable
+ let array = [2, 4, 6, 8];
+ let mut i = 0;
+ while i < array.len() {
+ let elem = array[i];
+ i += 1;
+ }
+ ```
+
+## More to Explore
+
+There's another way to express array iteration using `for` in C and C++: You can
+use a pointer to the front and a pointer to the end of the array and then
+compare those pointers to determine when the loop should end.
+
+```c,editable
+for (int *ptr = array; ptr < array + len; ptr += 1) {
+ int elem = *ptr;
+}
+```
+
+If students ask, you can point out that this is how Rust's slice and array
+iterators work under the hood (though implemented as a Rust iterator).
+
+