Note: Only numeric range iterators with <, ≤, >, ≥ and by have been implemented.
each makes it easier than while to iterate over a sequence of values. For example, here's the factorial function using each:
fn fact(n i32) i32: mut result = 1 each x in 2 ... n: result *= x result
Effectively this each statement binds the variable x to each iterated value from 2 up to n inclusively, each time performing the loop's inner block.
As this example shows, the each statement has a simple structure:
- One or more variables to be bound to values produced by the iterator. These variables are local to the each block and cannot be accessed outside that scope.
- An iterator that produces different value(s) on each iteration of the loop. The iterator follows in.
- A block containing the logic to be performed on each iteration.
break and continue
break and continue statements may be used within an each block to stop or re-start the loop.
Iterators
each supports several ways to iterate over a sequence of values:
- Number range, for simple arithmetic progressions.
- Collection, to work with individual elements within a collection.
- Closure, to deal with algorithmically-generated values.
Number Range Iterator
As the above example shows, the ... or .. range operator can be used to iterate successively over integers or floating point numbers. Iteration begins with the first number and then increments by 1 until it reaches (..) or passes (...) the second number. Expressions may be used in place of literal numbers, if desired.
To iterate backwards (decrementing the iterated number), use the > or >= operators instead.
each x in 6 > 1 // iterates: 6 5 4 3 2
A step value may be specified after by. Instead of incrementing or decrementing by 1, the step value specifies how much to increase the iterated number each time:
mut sum = 0 each x in 0 ... 10 by 2: // iterates: 0, 2, 4, 6, 8, 10 sum += x
Collection Iterator
each can be used to iterate through every element in a collection, one at a time. For example:
mut sum = 0 each x in [4, 3, 8, 2]: sum += x
Iteration can also capture the index or key for each element value:
each i, x in intslice: newslice[i] = x
Closure Iterator
Look to closures for iterator versatility. Using closure iterators, one can scan through elements in a complex collection, retrieve values from a streaming resource, algorithmically calculate a sequence of values, etc. Because closures are stateful, they can generate a new value on every call.
In order for a closure to be suitable as an iterator, it must be able to signal when it is done producing values. It typically does this by returning an optional value, with the value of None signalling when it is done.
In the following example, imagine a closure that starts off holding the value 12, and halves (and returns) its value on each call. When the value gets to 0, it returns None instead:
mut sum = 0 each x in |{cnt = 12}| if cnt > 0 {Some[cnt /= 2]} else {None}: sum += x
The value of sum at the end will be 10, as each successive call to the closure returns 6, 3, and 1. After 1, it returns None, which stops iteration.
Because it is stateful, a closure is typically single use. It is created before it is needed, used to produce values lazily, and then discarded afterward. This is because, unless its state can be independently reset, it will only ever afterward say it is out of values.
Automatic Closure Creation
Not uncommonly, we simply want to specify some resource, and have each automatically create a closure for iterating over the collection. For this reason, when a value is specified on each that is not already an iterator, a call to the iter method is implicitly made. iter is expected to return a closure iterator:
each x in collection // equivalent to: each x in collection.iter
Similarly, if an iterator is expected to return two values, the kviter method is implicitly invoked instead:
each key, value in dictionary