Iteration and indexing

Iteration and indexing

The Iter protocol

[public] trait Iter<T> {
    fn next() => T?;
    fn check() => bool;
}

for x in value lowers to: call value.iter(), then call next() on the result repeatedly, binding the loop variable to each value, stopping at the first None.

Two consequences:

  • There is no Iterable trait. Being iterable means having an iter() method that returns something with a next() yielding T?. The diagnostic says so directly: the type does not implement iter, which is required for for loops.
  • check() is never called by a for loop. It exists for driving an iterator by hand.

In the standard library only Array (and List, by inheritance) has iter(). Map, IndexMap, string, and JsonArray do not.

for name in names { }                 // works, Array
for key in map.key_list() { }         // the way to walk a Map
for (key, value) in map.entries() { } // or with both halves

Destructuring

for (a, b) in ... and let (a, b) = pair bind against a Pair, calling get_first() and get_second(). Exactly two names are supported, and the value has to be a Pair: anything else reports that it cannot be destructured.

This is how Map.for_each is written internally:

[public] fn for_each(action: closure(KT, VT) => void) {
    for (key, value) in this.entries() {
        action(key, value)
    }
}

Index and IndexRef

[public] trait Index<I, R>    { fn index(index: I) => R; }
[public] trait IndexRef<I, R> { fn index_ref(index: I) => &R; }

The compiler picks by context: reading a[i] calls index, while assigning a[i] = v needs a slot and calls index_ref.

Type a[i] a[i] = v
Array<T>, List<T> yes yes
string yes, yields char no

Neither is bounds checked.