for value in source uses the Iterable[T] protocol. The compiler asks the
source for an Iterator[T] and repeatedly calls next() until it returns
None.
for name in names {
println(name)
}Lists, strings, maps, sets, slices, and ranges provide iterable behavior.
Iteration does not imply indexed access. Write algorithms against
Iterable[T] when they only need sequential values; require a concrete list or
slice when they need indexing, length, or mutation.
Patterns
Loop bindings are patterns:
for index, value in values.enumerate() {
println("$index: $value")
}
for key, value in settings {
apply(key, value)
}Refutable loop patterns use the dedicated for pattern := expression form
described in Loops.
Iterators
Iterator[T] is one-shot:
trait Iterator[T] {
fn next(mut self): Option[T]
}An iterator is a stateful, one-shot cursor. Calling next() advances it.
Default consuming operations are:
| Method | Consumption |
|---|---|
for_each(f) |
Visits the remainder |
count() |
Counts and exhausts the remainder |
first() |
Consumes at most one item |
last() |
Exhausts and returns the final item |
any(f), all(f) |
Stop once the answer is known |
find(f) |
Stops at the first match |
After a short-circuiting call, the cursor remains positioned after the item that decided the result. Do not expect a consumed iterator to restart.
Lazy adapters return new iterators:
selected := source.iterator()
.filter(value => value.active)
.map(value => value.id)
.take(10)The current generic adapter set is deliberately small:
| Adapter | Behavior |
|---|---|
map(f) |
Transform each pulled item |
filter(f) |
Pull until an item passes |
take(n) |
Yield at most n items |
skip(n) |
Discard the first n items |
Adapters are lazy: constructing the chain does not visit the source. Work
happens when next() or a consuming method pulls values. A non-positive
take yields nothing; a non-positive skip skips nothing.
Collection methods with similar names often allocate eager lists. For example,
values.map(f) creates a list, whereas values.iterator().map(f) creates a
cursor. Choose based on whether the result must be stored or only traversed.
Iterable
Iterable[T] represents a repeatable source that can create an iterator. Its
associated iterator type is compiler-resolved:
trait Iterable[T] {
type Iter: Iterator[T]
fn iterator(self): Iter
}Implement Iterator for a stateful cursor and Iterable for the collection
that creates it. Avoid returning the same mutable cursor from repeated
iterator() calls.
Iterable also supplies eager for_each_item, count_items, and
first_item defaults. Each obtains a fresh iterator, so repeatable collections
can call them independently.
struct CountdownIter {
remaining: int
}
impl Iterator[int] for CountdownIter {
fn next(mut self): int? {
if self.remaining <= 0 {
return None
}
self.remaining -= 1
return Some(self.remaining)
}
}The iterator owns its progress. The collection’s iterator() method should
construct that progress state rather than mutate the collection itself.
Ranges
start..end is half-open; start..=end is inclusive. Integer ranges integrate
with for:
for index in 0..items.len() {
use(items.get(index))
}Prefer direct collection iteration when an index is not otherwise needed.
Half-open ranges compose naturally with zero-based lengths because the end is
excluded. Inclusive ranges are useful for closed numeric intervals. Range
syntax and the four for forms are specified in
Loops.