Iterators (std::Iter)
std::Iter provides lazy pipelines — each step only processes an item
when the next step requests it. No intermediate array is allocated until you
call collect() or each().
Range
Iter::range(start, end) produces the integers [start, end) without
materialising the array. It is the most common source for a pipeline:
Exclusive numeric sequence at the end; collect() materialises the array.
// Feature: Iter.range — lazy numeric sequence
// When to use: producing a source for a pipeline without materializing an array.
use std::Iter
// Simple range 0..5 (end exclusive).
let r = Iter::range(0, 5)
print(r.collect())
// expected: [0, 1, 2, 3, 4]
// Empty range when start >= end.
let empty = Iter::range(5, 5)
print(empty.collect())
// expected: []
// Sum from 1 to 10.
let sum = Iter::range(1, 11).fold(0, |acc, x| acc + x)
print(sum)
// expected: 55
// Range feeding map.
let squares = Iter::range(1, 6).map(|x| x * x).collect()
print(squares)
// expected: [1, 4, 9, 16, 25]
Map and Filter
map transforms each item; filter discards those that do not satisfy the
predicate. Chained together they form a linear-reading pipeline:
filter -> map -> collect with no intermediate arrays.
// Feature: Iter.map / Iter.filter — lazy transform and filter
// When to use: processing pipelines without allocating intermediate arrays.
use std::Iter
// map — transforms each item.
let doubled = Iter::range(1, 6).map(|x| x * 2).collect()
print(doubled)
// expected: [2, 4, 6, 8, 10]
// filter — keeps items that pass the predicate.
let evens = Iter::range(1, 11).filter(|x| x % 2 == 0).collect()
print(evens)
// expected: [2, 4, 6, 8, 10]
// Pipeline: filter -> map -> collect.
let it = Iter::range(1, 11)
let only_even = it.filter(|x| x % 2 == 0)
let squared = only_even.map(|x| x * x)
print(squared.collect())
// expected: [4, 16, 36, 64, 100]
Fold
fold(acc, |acc, x| ...) reduces the whole sequence to a single value — sum,
product, concatenated string:
Sum, factorial and sum of even squares with the same combinator.
// Feature: Iter.fold — reduce an iterator to a single value
// When to use: summing, multiplying, building a final string, counting.
use std::Iter
// Sum 1..10.
let sum = Iter::range(1, 11).fold(0, |acc, x| acc + x)
print(sum) // expected: 55
// Product 1..6 (= 5!).
let fact = Iter::range(1, 6).fold(1, |acc, x| acc * x)
print(fact) // expected: 120
// Sum of even squares from 1..10.
let it = Iter::range(1, 11)
let it2 = it.map(|x| x * x)
let it3 = it2.filter(|x| x % 2 == 0)
let result = it3.fold(0, |acc, x| acc + x)
print(result) // expected: 220
// String concatenation.
let nums = Iter::range(1, 4)
let joined = nums.fold("", |acc, x| acc + "{x};")
print(joined)
// expected: 1;2;3;
Take and Skip
take(n) limits how many items flow forward; skip(n) ignores the first ones.
Together they implement pagination on any iterator:
skip(1).take(3) — skips the header and takes the next three lines.
// Feature: Iter.take / Iter.skip — limit and skip elements
// When to use: pagination, taking first N, ignoring a stream header.
use std::Iter
// take — grabs the first N.
let first3 = Iter::range(0, 100).take(3).collect()
print(first3)
// expected: [0, 1, 2]
// skip — drops the first N.
let skip5 = Iter::range(0, 20).skip(5).take(4).collect()
print(skip5)
// expected: [5, 6, 7, 8]
// take beyond the length — stops at the end.
let small = Iter::range(0, 3).take(100).collect()
print(small)
// expected: [0, 1, 2]
// Skip the header of a "stream" (range simulating lines).
let lines = Iter::range(1, 11) // 10 items
let body = lines.skip(1) // ignore the "header"
let preview = body.take(3)
print(preview.collect())
// expected: [2, 3, 4]
Zip
zip combines two iterators into [a, b] pairs, stopping at the shorter one:
Value pairs and sum mapping with zip -> map.
// Feature: Iter.zip — combines two iterators into pairs
// When to use: pairing index/value, headers with columns, etc.
use std::Iter
// Simple zip — stops at the shorter side.
let a = Iter::range(1, 4)
let b = Iter::range(10, 14)
let pairs = a.zip(b).collect()
// Each pair is an [x, y] array.
print(pairs.len()) // expected: 3
print(pairs[0]) // expected: [1, 10]
print(pairs[1]) // expected: [2, 11]
print(pairs[2]) // expected: [3, 12]
// Zip stops at the shorter side — 3 items, not 5.
let short = Iter::range(0, 3)
let long = Iter::range(0, 5)
print(short.zip(long).collect().len())
// expected: 3
// Combine with map to sum pairs.
let xs = Iter::range(1, 5)
let ys = Iter::range(10, 14)
let zipped = xs.zip(ys)
let sums = zipped.map(|p| p[0] + p[1])
print(sums.collect())
// expected: [11, 13, 15, 17]
Collect and Each
collect() terminates the pipeline and returns an array. each() executes a
side effect per item and returns nil — useful for printing or accumulating
into an external variable:
collect returns an array; each is for effects — it returns no value.
// Feature: Iter.collect / Iter.each — terminate a pipeline
// When to use: collect when you need the array; each for side effects.
use std::Iter
// collect — materializes the iterator into an array.
let arr = Iter::range(1, 5).collect()
print(arr)
// expected: [1, 2, 3, 4]
print(arr.len()) // expected: 4
// each — runs a side effect per item, returns nil.
print("--- each ---")
Iter::range(1, 4).each(|x| print("item={x}"))
// expected: --- each ---
// expected: item=1
// expected: item=2
// expected: item=3
// Full pipeline: range -> filter -> map -> collect.
let it1 = Iter::range(1, 11)
let it2 = it1.filter(|x| x % 2 == 1) // odd numbers
let it3 = it2.map(|x| x * 10)
print(it3.collect())
// expected: [10, 30, 50, 70, 90]
Challenge
Build a pipeline that produces the first 5 odd numbers greater than 10 using
range, filter, take and collect. How many calls to filter are
executed?
See also