An iterator is a concept found in programming languages to refer to a construct which allows iterating over collections or sequences of elements. The concept is purposely vague, it's a concept! It does not prescribe any specific implementation.
To more easily distinguish C++ from Rust, I am going to use different names:
- C++ iterators will be named cursors,
- Rust iterators will be named streams.
Yes, those are completely arbitrary. Note that if you look at languages like Java or C#, you will find that they also use streams.
C++
First of all, don't use cplusplus.com. cppreference.com is much better.
An iterator is any object that, pointing to some element in a range of elements (such as an array or a container), has the ability to iterate through the elements of that range using a set of operators...
Simple, and wrong.
A cursor may either:
- point to an element,
- or be singular and point to no element at all.
In general, the singular value is used to represent:
- the end of the sequence to iterate over:
vec.end()
,
- the absence of an element:
std::find(...)
.
You can increment, and sometimes decrement, a cursor. If you do so, you however generally need a pair of cursors to know when to stop.
Why did C++ use such a representation? Because that's how C did it, and it works pretty well... although it's error prone.
Rust
Rust endeavors to be safe and favors APIs which are easy to use. This rules out a pair of cursors:
- a pair of cursors is not safe: you can easily iterate out of bounds, and you can obtain aliasing references,
- a pair of cursors is error-prone: it's easy to accidentally pair off cursors from two different sequences.
In order to control bounds, aliasing and avoid pair mismatch, you have to use a single object; thus the stream-like API.
The Iterator
API in Rust is reminiscent of that of Java and C#, although Rust improves upon it by using Option
so that instead of the clumsy hasNext()
/next()
call pair, it offers a single method next()
which both advances the stream and may signal its end.
Conclusion
Both Rust and C++ features a way to iterate over a collection of elements:
- C++ offers a C-like way, flexible but error-prone,
- Rust offers a modern way, safe but less flexible.
Both languages also offer external and internal iteration:
- External: the user controls the iteration (calls
++
or next()
),
- Internal: the iterator controls the user code (see
std::foreach
and Iterator::foreach
).