After bit after reviewing the code in https://github.com/rust-lang/rust/pull/75021 I had a thought: if this iterator is mostly just a wrapper on a slice iterator, does it even need to be an iterator at all?
The original .chunks() call does (as does .windows), because the slices it wants to return don't exist anywhere.
But the arrays returned by array_chunks are inline in the original slice allocation, so the API could just return the slice that the method is already creating, instead of hiding it in an iterator.
To be more concrete:
impl [T] {
pub fn array_chunks<const N: usize>(&self) -> (&[[T;N]], &[T]);
pub fn array_chunks_mut<const N: usize>(&mut self) -> (&mut [[T;N]], &mut [T]);
}
Not only would this be more general (the ArrayChunks type doesn't currently expose the slice), but I think it would make it less likely that people would forget to correctly handle the .remainder(). (While still being easy to ignore it with .0 if they insist.) And returning tuples like this has precedent with split_* and align_to and such. (Many other names could work too, like .as_chunks(_mut).)
Also, such a method would be nice to have as the inverse of a hypothetical flatten: &[[T; N]] -> &[T].
array_chunks tracking issue https://github.com/rust-lang/rust/issues/74985
Also related, array_windows in #75026 does have to be an iterator.
So it might be strange if array_chunks/_mut were the odd ones out.
(the
ArrayChunkstype doesn't currently expose the slice)
It could though, just as Iter does.
Let's compare the usage examples with the iterator and the slice.
Also, such a method would be nice to have as the inverse of a hypothetical
flatten: &[[T; N]] -> &[T].
~#62765 indicates that's not allowed, at least in the general case where you don't know whether those slices really come from the same allocation rather than just happening to be adjacent by coincidence.~
That's not multiple slices -- a slice of arrays is necessarily just one contiguous allocation.
The chunks_exact function that array_chunks bases on also has a reverse analog: rchunks_exact where it iterates the chunks in reverse order, starting at the end. Obviously for this instance, one can't get a slice that has precisely the same behaviour. But maybe it's enough to tell people that they still need to do .iter().rev() if they want to traverse the slice of array chunks in reverse order?
The important difference with rchunks to me is that the remainder goes at the beginning, not the end. So I agree that saying "use .rev() to go backwards" would be fine.
So that would imply that there'd be both of these
as_chunks: &[T] -> (&[[T; N]], &[T]) #76635as_rchunks: &[T] -> (&[T], &[[T; N]])I can go make a PR for the second one of those, if it sounds worthwhile...
Most helpful comment
That's not multiple slices -- a slice of arrays is necessarily just one contiguous allocation.