Iterator take skip and while bounds
take and skip bound an iterator by count, while take_while and skip_while bound it by an initial run of items matching a predicate.
What it is
Iterator::take(n) yields at most the first n items.
It is the standard way to make a finite prefix from a longer or infinite iterator.
Iterator::skip(n) discards at most the first n items, then yields the rest.
Iterator::take_while(predicate) yields items only while the predicate returns true.
Once the first false appears, it stops permanently.
Iterator::skip_while(predicate) discards items only while the predicate returns true.
Once the first false appears, it yields that item and every remaining item.
The while adapters are prefix-oriented, not whole-stream filters.
Use filter when every item should be tested independently.
Use these methods for headers, prefixes, pagination, sentinels, and bounded sampling.
How it works
take stores a remaining count.
Each successful next decrements the count until it reaches zero.
skip consumes from the upstream iterator until the skip count is exhausted or the upstream iterator ends.
Then it passes through later items.
take_while and skip_while receive predicates of type FnMut(&Self::Item) -> bool.
Like filter, this can produce &&T closure arguments when the upstream iterator yields references.
take_while must inspect the first failing item to know that it should stop.
For a consuming iterator, that failing item is consumed and not returned later.
skip_while yields the first item that fails the predicate.
All four adapters are lazy and preserve order.
They are often combined with by_ref when part of an iterator should be consumed and the rest reused.
Example
fn main() {
let mut words = ["header", "body", "body", "tail"].into_iter();
let first_two: Vec<_> = words.by_ref().take(2).collect();
let rest: Vec<_> = words.collect();
assert_eq!(first_two, ["header", "body"]);
assert_eq!(rest, ["body", "tail"]);
}Edge cases
fn main() {
let values = [1, 2, 0, 3, 4];
let before_zero: Vec<_> = values
.into_iter()
.take_while(|&n| n != 0)
.collect();
assert_eq!(before_zero, [1, 2]);
let after_prefix: Vec<_> = [-2, -1, 0, -3]
.into_iter()
.skip_while(|n| *n < 0)
.collect();
assert_eq!(after_prefix, [0, -3]);
}Best practice
- ✅ Use
taketo cap infinite iterators before collecting. - ✅ Use
skipandtaketogether for simple offset-limit pagination. - ✅ Use
take_whilefor a prefix that ends at a sentinel. - ✅ Use
skip_whilefor dropping a leading prefix only. - ✅ Use
filterwhen later matching items should still be considered. - ✅ Use
by_refwhen you need to keep using the original iterator after a partial consume. - ✅ Pattern-match predicate parameters to handle references clearly.
- ✅ Document whether the boundary item is kept or consumed for sentinel parsing.
Pitfalls
- ⚠️
take_whileconsumes the first item that returnsfalseon a consuming iterator. - ⚠️
skip_whilestops testing after the firstfalse; later matching items are still yielded. - ⚠️
take(n)on a shorter iterator just yields fewer items, with no error. - ⚠️
skip(n)on a shorter iterator yields an empty iterator, with no error. - ⚠️ Collecting a huge or infinite iterator before
takedefeats the point; see Unnecessary Collect. - ⚠️ Double-reference predicates can obscure intent.
- ⚠️ Using
skipfor large offsets on non-random-access iterators still advances through skipped items. - ⚠️ Forgetting
by_refmoves the iterator into the adapter and prevents later direct use.
See also
std: Iterator Adapter Catalog · Iterator map and filter · Iterator predicate search adapters · Iterator chain cycle and step_by · Iterator flat_map and flatten · Iterator collect and FromIterator · Iterator Adapters · Lazy Evaluation · Borrowing · Unnecessary Collect · Iterating Collections
Sources
- Rust standard library,
Iterator::take- std, https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.take - Rust standard library,
Iterator::skip- std, https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.skip - Rust standard library,
Iterator::take_while- std, https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.take_while - Rust standard library,
Iterator::skip_while- std, https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.skip_while
