Note: Only numeric range iterators have been implemented.
Although while can be used to implement any structured loop, each makes it more convenient to implement a common loop pattern: iterating over a sequence of values. Let's re-implement 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. This uses the same inclusive range operator ... described earlier for match.
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.
Each clause, break and continue
each is like while in two more ways. It may be used as a statement suffix:
fn fact(n i32) i32 mut result = 1 result *= x each x in 2 ... n result
Also, break and continue statements may be used within an each block to stop or re-start the loop.
Several forms of iterators may be used.
Numeric Range Iterator
As the above example shows, the .. and ... range operators 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
each can be used to iterate successively through every element in an array or array reference (slice) data structure, one at a time. For example:
mut sum = 0 each x in intslice sum += x
Iteration can return a mutable borrowed reference instead of the value:
each &mut x in intslice ++x
Iteration can also show the index number for each value:
each i, x in intslice newslice[i] = x
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. We will cover closures in much more detail later. For now, think of a closure as a function that preserves and uses its state from one call to the next. When a closure is used as an iterator, it produces 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 does this by returning a special value when it is done, typically none or null.
In the following example, imagine that half is 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 half sum += x
The value of sum at the end will be 10, as each successive call to half 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
The typical approach is to create the closure iterator as part of the each statement. For example:
each x in collection.iter
If what is specified is not already an iterator, an implicit call to the iter method is made. Thus, the above can be rewritten as:
each x in collection
Similarly, if an iterator is expected to return two values, the kviter method is expected instead:
each key, value in dictionary