Iterable and Collections

We have learned that instances of Array, ArrayList and other collection types, as well as Range, can be traversed using a for-in loop expression. Can a user-defined type be traversed in a similar way? Yes.

Range, Array, ArrayList, etc., all use the Iterable interface to support the for-in syntax.

Iterable<T> is a built-in interface of the following form (non-essential code is omitted):

interface Iterable<T> {
    func iterator(): Iterator<T>
    ...
}

The iterator member function, in turn, returns a value of the Iterator<T> type, another built-in interface type of the following form (again, only the relevant code is shown):

interface Iterator<T> <: Iterable<T> {
    mut func next(): Option<T>
    ...
}

You can use the for-in syntax to traverse an instance of any type that implements the Iterable<T> interface for a certain type T (which can also be a type variable).

Assume that there is such a for-in expression:

let list = [1, 2, 3]
for (i in list) {
    println(i)
}

It is actually equivalent to the following while loop expression:

let list = [1, 2, 3]
var it = list.iterator()
while (true) {
    match (it.next()) {
        case Some(i) => println(i)
        case None => break
    }
}

Another common method for traversing an instance of an Iterable type is to use while-let. For example, another equivalent writing method of the while code above is as follows:

let list = [1, 2, 3]
var it = list.iterator()
while (let Some(i) <- it.next()) {
    println(i)
}

The Array, ArrayList, HashSet, and HashMap types all implement Iterable. Therefore, their instances can be used in a for-in or while-let expression. You can have the types that you define implement Iterable to enable such traversal.