Iterators
chunks() and Windows Through Standard-Library Alternatives
While the Iterator trait operates on one element at a time, contiguous slices (&[T] and &mut [T]) provide specialized iterators for fixed-size batching (.chunks(), .chunks_exact(), .as_chunks()) and overlapping sliding windows (.windows()).
Slice Chunking and Windowing Methods
| Slice Method | Step Size | Remainder Behavior | Yielded Item Type |
|---|---|---|---|
slice.chunks(n) |
n (non-overlapping) |
Final slice has length 1..=n if len % n != 0 |
&[T] |
slice.chunks_exact(n) |
n (non-overlapping) |
Guarantees every yielded slice has length n; remainder accessed via .remainder() |
&[T] |
slice.as_chunks::<N>() |
N (const generic) |
Returns (&[[T; N]], &[T]) — fixed-size array references + remainder slice |
(&[[T; N]], &[T]) |
slice.rchunks(n) |
n (from the back) |
Final slice at the front has length 1..=n |
&[T] |
slice.chunk_by(pred) |
Variable (runs) | Splits wherever pred(&a, &b) returns false |
&[T] |
slice.windows(n) |
1 (overlapping) |
Yields 0 items if slice.len() < n |
&[T] (each of length n) |
Slice: [ 10, 20, 30, 40, 50 ]
.chunks(2): [10, 20], [30, 40], [50] (non-overlapping)
.chunks_exact(2): [10, 20], [30, 40] (remainder: [50])
.windows(3): [10, 20, 30]
[20, 30, 40]
[30, 40, 50] (sliding by 1)
Non-Overlapping Batches with .chunks() and .chunks_exact()
fn main() {
let data = [1, 2, 3, 4, 5, 6, 7];
let chunks: Vec<&[i32]> = data.chunks(3).collect();
println!("chunks(3): {chunks:?}");
let mut exact = data.chunks_exact(3);
println!("exact batch 1: {:?}", exact.next().unwrap());
println!("exact batch 2: {:?}", exact.next().unwrap());
println!("exact remainder: {:?}", exact.remainder());
}
chunks(3): [[1, 2, 3], [4, 5, 6], [7]]
exact batch 1: [1, 2, 3]
exact batch 2: [4, 5, 6]
exact remainder: [7]
Overlapping Sliding Windows with .windows()
slice.windows(size) is ideal for computing moving averages, finite differences, or checking sorted adjacency across a slice:
fn main() {
let prices = [100_i32, 105, 102, 110, 118];
// Compute day-over-day price deltas using 2-element windows:
let deltas: Vec<i32> = prices
.windows(2)
.map(|w| w[1] - w[0])
.collect();
// Group consecutive ascending runs using `chunk_by`:
let ascending_runs: Vec<&[i32]> = prices
.chunk_by(|a, b| a <= b)
.collect();
println!("Price deltas: {deltas:?}");
println!("Ascending runs: {ascending_runs:?}");
}
Price deltas: [5, -3, 8, 8]
Ascending runs: [[100, 105], [102, 110, 118]]
Why Iterator Does Not Have a Zero-Allocation .windows() Method
slice::windows returns &[T] views directly into an already contiguous memory buffer in $O(1)$ time. A general Iterator produces values on the fly that are not stored contiguously in memory, so windowing an arbitrary Iterator requires either copying elements into a ring buffer or requiring Item: Clone.