The for loop
A for loop runs a block of code once for each item in a collection such as an array. You don't manage indices yourself: Scala hands you each item in turn.
val fruits = Array("banana", "orange", "pear", "kiwi")
for (fruit <- fruits) {
println("I eat " + fruit)
}
The output is one line per fruit:
I eat banana
I eat orange
I eat pear
I eat kiwi
Reading the syntax
forstarts the loop.fruitis the loop variable. On each pass it holds the current item. You choose its name, and it exists only inside the loop. You don't declare it withval.<-is the generator arrow. Read it as "in": the whole header says "for eachfruitinfruits".fruitsis the collection to walk through, in order from the first element to the last.- The part in braces is the body, which runs once per item.
An array with four elements runs the body four times. An empty array runs it zero times, and nothing is printed.
The exercise: greeting friends
The starting code has an array of names:
val friends = Array("Andy", "Mary", "John")
- Write the loop header. The lesson asks for a loop variable named
friendover thefriendsarray:for (friend <- friends). The singular name for the item and the plural name for the collection make the header read naturally. - Print the greeting inside the body. The message is
Hey, Andy!with each name in turn. Ansstring inserts the variable: ins"Hey, $friend!"the$friendis replaced by the current name.
val friends = Array("Andy", "Mary", "John")
for (friend <- friends) {
println(s"Hey, $friend!")
}
The output is:
Hey, Andy!
Hey, Mary!
Hey, John!
Details worth knowing
- Interpolation needs the
s. Without it,"Hey, $friend!"is printed literally, dollar sign included. - The punctuation after the name is safe. In
$friend!, the!can't be part of a name, so the interpolation stops there. If the next character could belong to a name, use braces:${friend}s. - The array is not changed. The loop only reads each item. Assigning to
friendinside the body is not allowed, because the loop variable can't be reassigned. - Other collections work the same way.
List,Vector,ArrayBufferandSetcan all go to the right of<-.
Loops with indices and ranges
When you also need the position of each item, loop over the indices, or pair each item with its index using zipWithIndex:
for (i <- friends.indices) {
println(i + ": " + friends(i))
}
for ((friend, i) <- friends.zipWithIndex) {
println(s"$i $friend")
}
The first loop prints 0: Andy, 1: Mary and 2: John. The second prints 0 Andy, 1 Mary and 2 John. Ranges also work as collections: 1 to 3 includes 3 and counts 1, 2, 3, while 1 until 3 stops before 3 and counts 1, 2. Looping with 0 to friends.size would include the invalid index 3, so loop with until or indices when you use indices.
Common mistakes
- Writing
inor:instead of<-. Scala's generator is the arrow. - Using a name that doesn't match. If the header says
friend, the body must sayfriend, notfriends. Using the array name inside the body prints the array object, not one name. - Looking for a loop counter. There is none unless you ask for indices.
Key takeaways
for (item <- collection) { ... }runs the body once for each item, in order.- The loop variable takes each value in turn and is only visible inside the loop.
- Use an
sstring to put the loop variable into the printed message. - Use
indices,zipWithIndexoruntilwhen positions matter.
