Closed scottmcm closed 3 years ago
Consider IntoIterator::into_iter(0..5) instead of (0..5).into_iter(). It's minor, but emphasizes that it has to be the trait, not an inherent method nor something reachable via auto(de)ref.
That's definitely the more correct version but I deliberately opted to use method syntax with a later note about IntoIterator
because it's easier for a newbie to understand (lies to children and all that).
Chances are if you understand how autoref works you will recognise that we explicitly require an IntoIterator
implementation (instead of ducktyping) because of the error messages coming from rustc
.
It's more like how C++ does slice iterators
That's actually where I got the inspiration from!
I like it because it makes next()
and next_back()
very easy to implement and it is easy for me to visualise - you just imagine a strip of cells where your index fingers point at the start and end of the section you care about, then popping from the front/back is just a case of moving a finger inwards until they touch.
My main concern is that the version with start and end pointers will fall over when it comes to zero-sized types and treat all slices as empty. I'm not a big fan of how std
hijacks the end pointer to be ptr+len
because it litters the code with if mem::size_of::<T>() == 0
and treats a pointer as an integer, but it's probably the best we can do without having some sort of where mem::size_of::<T>() == 0
specialisation using const generics on slice's IntoIterator
impl.
Yeah, ZSTs definitely make everything a mess.
Slice iterators are definitely a special case for so many things, though. They're so core to everything that they include a bunch of tiny little things (like https://github.com/rust-lang/rust/pull/61885) that would never make sense in "normal" code.
Great post! I had a few minor comments, none of which are really problems, but here they are:
1) Consider
IntoIterator::into_iter(0..5)
instead of(0..5).into_iter()
. It's minor, but emphasizes that it has to be the trait, not an inherent method nor something reachable via auto(de)ref.2) I love the use of
?
innext
to handle the ending condition. There's a subtle beauty to it.3) There are a few reasons the pointer version is good:
NonNull<T>
to allow for niche optimization. Of course the slice versions get that automatically.)