What is an iterator in Rust

C++ is really an odd duck when it comes to iterators, so you may have a bit to unlearn.

C++ is based on C, and in C there is no such thing as an iterator. When you want to iterate over something, you write a loop. It usually looks something like this:

for (c = begin(); c != end(); ++c) {...}

c could be a pointer, but it might also be an integer. Basically it represents a position in a range. We could call it a cursor.

Cursors are in a sense a lower-level abstraction than iterators. You can use a cursor to iterate over a range, but that's not all you can do. You can advance a cursor by several steps at a time, skipping some values, or you can follow (dereference) the cursor several times without advancing it, processing the same value more than once. Cursors may also be moved backward as well as forward (C++ calls these "bidirectional iterators"). Some cursors can move instantly to any other position in the range without moving through the intermediate positions (C++ calls these "random access iterators"). All these things are reasonable to do in a cursor-based API, but they don't really have anything to do with iteration.

Rust's iterators are firmly grounded in iteration. An iterator is just something that produces items from a sequence one at a time. The sequence can be anything, like "all the odd numbers from 1 to 1000 in increasing order" or "ten million random strings" or "just the number 0.04, repeated forever". But the idea of an iterator is an object that can produce things from a sequence one at a time.

That doesn't mean you can't do a lot of the same stuff with iterators that you can with cursors! For instance, you can skip an item in the sequence by calling next() without using the value it returns, or you can skip a bunch of items by using nth(10). But this is still fundamentally iteration, so calling nth(10) should have the same effect as calling next() 11 times and just discarding the first 10 values. It's not the same as doing i += 10 for a "random access iterator" in C++. Random access falls outside of Rust's concept of iteration.

Rust iterators are more limited than cursors. This is a common pitfall for people coming from C++ because in C++ you always use the iterator API for abstracting over collections, and Rust iterators just don't provide the same control. Often this happens because you're trying to go too abstract too soon. For instance, in C++ you might use a random access iterator where in Rust you should just use a slice, as has come up in your other thread.

10 Likes