If a structure a has a member function operator iter(), the code
for(var i : a) {
<statements>
}
is syntactic sugar for
for(var it=a.operator iter(); it.valid(); it.advance()) {
var i=it.get();
<statements>
}
Thus, we can make a structure iterable by defining an operator iter
method that returns an object with the following methods:
T get() ¶returns the value at the iterator’s current position (without changing the
position). Note that T can be any type, builtin or user-defined;
void advance() ¶advances the iterator to the next position;
bool valid() ¶returns true if the iterator is at a valid position or false
if the iterator has advanced past the last item.
Although the return type of operator iter can theoretically be any type
that has these three methods, it is strongly recommended to use the
Iter_T structure defined in the templated module
collections.iter(T) so that other utilities
(see Iterators and utilities) can be used with the
iterator. The three methods of this structure can be set as fields.
As an example, here is an iterator for the even-numbered elements of an array of strings:
from collections.iter(T=string) access
Iter_T as Iter_string,
Iterable_T as Iterable_string;
struct EvenStrings {
string[] a;
void operator init(string[] a) {
this.a=a;
}
Iter_string operator iter() {
int i = 0;
Iter_string result;
result.get = new string() { return a[i]; };
result.advance = new void() { i += 2; };
result.valid = new bool() { return i < a.length; };
return result;
}
autounravel Iterable_string operator cast(EvenStrings es) {
Iterable_string result;
result.operator iter = es.operator iter;
return result;
}
}
string[] a = {'a', 'b', 'c', 'd', 'e', 'f'};
for (string s : EvenStrings(a)) {
write(s);
}
Running this code prints out the following:
a c e
The autounraveled (see Autounravel) implicit cast
to Iterable_string is not strictly necessary, but it allows
the use of iterable utilities; see Iterators and utilities.
This enables code like the following, which uses the enumerate
utility to attach counters to the iterated strings:
from collections.enumerate(T=string) access enumerate;
for (var kv : enumerate(EvenStrings(a))) {
write(string(kv.k) + ": " + kv.v);
}
Running this code prints out the following:
0: a 1: c 2: e