Iterators are a convenient way to traverse collections. A collection contains multiple elements of the same type (think vector, hashmap, tree, etc.), i.e. it makes sense to traverse it.
Let's look at what code looks like with or without iterators. We have a list of people (type Person), which we want to traverse.
Without iterators, this is a for loop with an index.
With iterators, this is a "range for" with an .iter() call.
3/ Iterator types
Some of the main types are:
* iter()
* iter_mut()
* into_iter() - which is also the default
4/ Complex iterator ops
If you've written a map or filter on a collection, then you have already used this.
Let's say we wanted to get all people whose first or last name start with a J, and format their name from Firstname Lastname to F. Lastname.
This can be a bit difficult to read at first, let's go step by step and understand the code generating formatted_names.
One way to simplify thinking about this is that at each step we are taking in an object, like person, and we need to convert it to another type. For example:
Filter - we map Person -> bool, where the bool is whether any of the names starts with a J
Map - we map Person -> String, where the String is the newly formatted name
At each step, all we need to do is figure out is what code to write to map the two types.
5/ Laziness
We have discussed how to use iterators, but now much about how they work internally. Think of an iterator as an object with a next function. You call next, you get the next item. When you reach the end next returns None and you know to stop iterating.
Having an iterator object doesn't mean you are actually iterating. Someone needs to call next.
This is at the core of laziness. We use filter and map to get an iterator object which captures what transformation we want to make to the original iterator.
But we don't actually *execute* that transformation until we call collect.
Let's see how this works.
Let's call filter, and print the result.
Notice this is Filter { iter: <full list which includes Anton Fu> }.
This means our filter didn't actually get executed.
We call collect and now the filter is executed.
This is because iterators are *lazy*, they will not get executed until we trigger it, in Rust using ::collect<>.
This was a gentle intro to Iterators in Rust, why they are useful, how to use them, complex filter/maps and laziness.
• • •
Missing some Tweet in this thread? You can try to
force a refresh
Context: I started off with ggez + specs and a very basic understanding of #rustlang and the game I wanted to make. I decided to investigate macroquad+hecs as an alternative and ended up attempting a re-write. This is a thread about my attempt!
✍️ How much did you actually rewrite vs reuse?
I started with an empty main. I asked myself how each thing was implemented before and if it still made sense. I reused some of the components I had from before but I also changed a lot. Some core ideas stayed and some changed.
⏱️ How long did it take?
Judging from the commits and dates, I think it took about 12-14 hours of development. One thing to note is that a rewrite was only possible in this time because my understanding of both rust and the task have significantly improved since I first started.