#204 Jun 15, 2026

204. take_while / skip_while — Act on the Leading Run, Not Every Match

Reaching for .filter() to drop leading blank lines? It’ll drop the blank lines in the middle too. take_while and skip_while work on the leading run and stop the moment the predicate flips.

The Problem

You want everything after the leading comment/blank lines in a config — but filter has no concept of “leading”:

1
2
3
4
5
6
7
8
9
let lines = ["# header", "", "key = 1", "", "key = 2"];

// Wrong: this also eats the blank line between the two keys
let body: Vec<&str> = lines
    .iter()
    .copied()
    .filter(|l| !l.is_empty() && !l.starts_with('#'))
    .collect();
assert_eq!(body, ["key = 1", "key = 2"]); // lost the structure

filter tests every element independently, so it strips matches wherever they appear. That’s rarely what “skip the header” means.

The Fix: skip_while

skip_while discards elements while the predicate holds, then yields the rest untouched — including later elements that would have matched:

1
2
3
4
5
6
7
8
let lines = ["# header", "", "key = 1", "", "key = 2"];

let body: Vec<&str> = lines
    .iter()
    .copied()
    .skip_while(|l| l.is_empty() || l.starts_with('#'))
    .collect();
assert_eq!(body, ["key = 1", "", "key = 2"]); // blank line kept

The blank line between the keys survives because skip_while already stopped skipping at "key = 1".

Its Mirror: take_while

take_while yields the leading run and stops at the first non-match — perfect for parsing a prefix:

1
2
3
4
5
6
7
let input = "42px";

let digits: String = input.chars().take_while(|c| c.is_ascii_digit()).collect();
let unit: String = input.chars().skip_while(|c| c.is_ascii_digit()).collect();

assert_eq!(digits, "42");
assert_eq!(unit, "px");

take_while halts at 'p', so even a trailing "9" in the unit wouldn’t sneak back into digits. Unlike filter, both adapters care about position: they describe the boundary between a leading run and everything after it.

← Previous 203. Peekable::next_if_map — Consume a Token Only If It Parses, Transform in One Step