Olivia Ifrim 🦀 Profile picture
👩‍💻 staff eng @twitter, before @microsoft @amazon @daisie 🦀 tweet a lot about rust and rust gamedev ✍️ wrote https://t.co/DolyQjGkcZ

Jan 6, 2022, 12 tweets

🧵 Introduction to @rustlang iterators 🦀 👇

doc.rust-lang.org/std/iter/trait…

1/ What are iterators?

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.

This is not a Rust specific concept, see en.wikipedia.org/wiki/Iterator#…

2/ Before/After iterators

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.

Share this Scrolly Tale with your friends.

A Scrolly Tale is a new way to read Twitter threads with a more visually immersive experience.
Discover more beautiful Scrolly Tales like this.

Keep scrolling