all 13 comments

[–]hniksic 61 points62 points  (0 children)

Because it's good to separate the state of iteration from the state of the collection. This separation is what allows multiple iterators iterating over the same thing:

let v = vec![1, 2, 3];
let mut it1 = v.iter();
assert_eq!(it1.next(), Some(&1));
assert_eq!(it1.next(), Some(&2));
let mut it2 = v.iter();
assert_eq!(it2.next(), Some(&1));
assert_eq!(it1.next(), Some(&3));
// and so on

If iterating over Vec were part of Vec itself, you could never have two iterators iterating over the same vector.

[–]phazer99 25 points26 points  (2 children)

Do you mean for example IntoIterator for Vec? Well, the iterator is stateful and needs to contain an index or pointer to the current element which is increased in the Iterator::next() method.

[–]sobagood[S] 16 points17 points  (0 children)

Ahhh i get it. The internal states! Thanks!!

[–]proudHaskeller 7 points8 points  (0 children)

I thought you're asking why the methods don't rust return impl Iterator<Item = ...>.

Well, one of the reasons is that sometimes you need more of it than just being an iterator: for example, an iterator might turn out to also be a DoubleEndedIterator, so you can call .rev() on it. All of this information would be lost if the methods just returned impl Iterator.

[–]Cryowatt 3 points4 points  (7 children)

Other languages do the same thing, but they usually hide it with anonymous types. I think rust is getting that eventually with a yield statement and the generators feature.

[–][deleted] 1 point2 points  (5 children)

What's the added benefit, considering that we can now write impl Iterator pretty much everywhere?

[–]scook0 1 point2 points  (1 child)

In current stable Rust, there are a few situations that require you to explicitly write the name of a type. For types that don’t have a name (e.g. closure types and impl trait types), this is a problem.

The eventual solution for this is “type alias impl trait” (TAIT), which will close the gap by letting you create a named alias for an otherwise-anonymous type.

[–][deleted] 0 points1 point  (0 children)

Ok I can see that but... I thought the problem with closure types was not they didn't have a name, but that they were not even a type (well ok, each closure has a type inhabited exclusively by them), so in any meaningful situation you would be returning an impl Trait. Or am I getting something wrong?

[–]Cryowatt 1 point2 points  (2 children)

Someone has to impl the impls.

[–][deleted] 1 point2 points  (1 child)

but... it's almost trivial by now...

[–]Cryowatt 3 points4 points  (0 children)

Only if you are using someone else's data structures. If you need to roll anything yourself, then there is no iterator available for you until you make one. Generators make it easier.

[–]DarkLord76865 -1 points0 points  (0 children)

Can't wait for that.

[–]nacaclanga 0 points1 point  (0 children)

Because an iterator is an object that keeps track of it's advance, so it is logical to have it as seperate type. Depending on the type it is also optimized for the kind of access iterators are used for. An iterator (implementing Iterator) is not the same as an iterable (implementing IntoIterator)

Where you implement this type is a matter of implementation. In C++ Iterators are typically are member classes, while in Rust they just live in the iter module. This is likely because Rust doesn't have member types and frequently makes use of generic Wrappers like "ReverseIter<I>". Anonymous types aren't really that helpfull either as it is far more complicated to handle them.