Learning Kotlin: The For Loop
Note This is the 20th post in a multipart series. If you want to read more, see our series index.
Kotlin has two loops: while and for. When I started, I was like, "yup, I know those..."—except I didn’t. while works the way I expected it would, but for is something else. First, Kotlin doesn’t have a traditional for loop, like for (var i = 0; i < max; i++). Instead, the for loop in Kotlin is closer to the iterator foreach loop in C#.
Basic
Let’s start with the basics: how do I run a loop, say, 10 times, where we print out 0, 1, 2, 3, 4, 5, 6, 7, 8, 9?
fun main(args: Array<String>) {
for (i in 0..9) {
println(i)
}
}
In this example, we use a ClosedRange (0..9) to state the start and end of the loop. This is equivalent to for (var i = 0; i < 10; i++).
Now, normally we want to loop over an array of items, and we can do this in two ways. First, the equivalent of C#’s for iterator or JavaScript’s for...of:
fun main(args: Array<String>) {
val a = arrayOf("The", "Quick", "Brown", "Fox")
for (i in a) {
println(i)
}
}
And if we use the older style of a normal for loop with an index:
fun main(args: Array<String>) {
val a = arrayOf("The", "Quick", "Brown", "Fox")
for (i in 0 until a.size) {
val value = a[i]
println(value)
}
}
What’s awesome here is the Range. Unlike the inclusive bounds of .., the until keyword gives us an exclusive upper bound.
Kotlin is all about helpers, and since we looked at destructuring last time, it shouldn’t be a surprise that we can use it to include both the index and the value in the for loop:
fun main(args: Array<String>) {
val a = arrayOf("The", "Quick", "Brown", "Fox")
for ((i, value) in a.withIndex()) {
println("$i is $value")
}
}
Extras
The for loop has two additional options worth knowing:
downTo, which loops from largest to smallest. This example prints4321:for (i in 4 downTo 1) print(i)step, which controls how many steps to take between iterations. In this example, we get42:for (i in 4 downTo 1 step 2) print(i)
Operator Overloading
Adding support for this to our own classes is trivial—just add the Iterator interface. This introduces two methods:
fun next(): T(returns the next value in the collection)fun hasNext(): Boolean(returnstrueif more values exist)
Let’s implement this with a PrimeNumbers class. Since there are infinite primes, we’ll add a top bound (maxToHunt), which forces the loop to eventually end. In next(), we not only return the current prime but also calculate the next next value to efficiently track whether more primes exist.
class PrimeNumbers : Iterator<Int> {
var currentPrime = 1
val maxToHunt = 100
var morePrimesToFind = true
override fun next(): Int {
val result = this.currentPrime
this.currentPrime += 1
while (this.currentPrime < this.maxToHunt) {
var primeFound = true
for (divisor in this.currentPrime - 1 downTo 2) {
if (this.currentPrime % divisor == 0) {
this.currentPrime += 1
primeFound = false
break
}
}
if (primeFound) break
}
this.morePrimesToFind = this.currentPrime < this.maxToHunt
return result
}
override fun hasNext() = this.morePrimesToFind
}
fun main(args: Array<String>) {
for (i in PrimeNumbers()) {
println("$i is prime")
}
}