#214 Jun 20, 2026

214. slice::windows — Compare Consecutive Elements Without the Index Math

The classic “look at each element and the next one” loop is a panic waiting to happen: 0..v.len() - 1 underflows the moment the slice is empty. windows hands you every consecutive pair safely, no arithmetic required.

Whenever you need to look at neighbouring elements — deltas between samples, “is each one bigger than the last”, spotting a transition — the reflex is to index by hand:

1
2
3
4
5
6
let v = [3, 7, 2, 9];

for i in 0..v.len() - 1 {
    let diff = v[i + 1] - v[i];
    // ...
}

This works until v is empty. v.len() is 0, v.len() - 1 underflows on usize, and the loop panics before it even starts. You end up bolting on an if !v.is_empty() guard, and the v[i + 1] indexing still pays a bounds check every iteration.

slice::windows(n) gives you an iterator of overlapping sub-slices of length n. Ask for 2 and you get each consecutive pair, with no index juggling and no empty-slice trap:

1
2
3
4
5
6
7
let v = [3, 7, 2, 9];

let diffs: Vec<i32> = v.windows(2)
    .map(|w| w[1] - w[0])
    .collect();

assert_eq!(diffs, vec![4, -5, 7]);

Because windows yields nothing when the slice is shorter than n, the empty and single-element cases just fall out for free — no special handling:

1
2
3
4
5
let empty: [i32; 0] = [];
assert_eq!(empty.windows(2).count(), 0);

let one = [42];
assert_eq!(one.windows(2).count(), 0);

It composes with the rest of the iterator toolbox, too. Checking that a slice is strictly increasing becomes one readable line:

1
2
3
let v = [1, 4, 6, 10];
let strictly_increasing = v.windows(2).all(|w| w[0] < w[1]);
assert!(strictly_increasing);

The window size isn’t limited to 2 — pass 3 for sliding triples (handy for smoothing or peak detection), and each window is a real slice you can index, sum, or pattern-match:

1
2
3
let v = [1, 2, 3, 4, 5];
let sums: Vec<i32> = v.windows(3).map(|w| w.iter().sum()).collect();
assert_eq!(sums, vec![6, 9, 12]);

One caveat: the windows overlap and share elements, so windows only hands out shared (&) references — you can’t mutate through them. When you want non-overlapping fixed-size groups instead, reach for chunks. But for anything that compares an element to its neighbours, windows replaces the fragile len() - 1 loop with code that can’t go out of bounds.

← Previous 213. abs_diff — The Gap Between Two Numbers, No Underflow, No Overflow Next → 215. next_multiple_of — Round Up to a Multiple Without the +m-1 Dance