for loops
No while. No do-while. No separate infinite-loop keyword. Go has exactly one loop word, for, and all three shapes you would reach for in other languages are just different arrangements of the same for.
The classic counter
The three-part form will look familiar: an init statement, a condition, and a post statement, separated by semicolons.
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// prints 0, 1, 2, 3, 4
Each of the three parts runs at a different point:
- The init runs once, before the loop starts. Usually a declaration or assignment that sets up the loop variable.
- The condition is checked before every iteration. If it is
true, the body runs; iffalse, the loop exits. - The post runs after every iteration body, before the next condition check. Usually the thing that moves the loop forward.
For i := 0; i < 5; i++: i starts at 0; Go checks 0 < 5 (true, runs the body), prints 0, runs i++ to make i equal to 1, checks 1 < 5 (true), and so on until i is 5, where 5 < 5 is false and the loop exits.
i is scoped to the loop. It disappears once the loop exits. Note also that i++ is a statement, not an expression (as you saw in the operators lesson), so it can only appear on its own line or as the post part of a for. That rules out tricks like j = i++ or arr[i++] = x that you may remember from C; in Go you increment on a separate line and use i afterwards.
The condition-only form (Go's while)
Drop the init and post, keep only the condition, and you have Go's equivalent of while:
n := 1
for n < 100 {
n *= 2
}
// n is now 128
The parser uses the absence of semicolons to tell this apart from the three-part form. Some people find it strange that Go reuses for for this shape, but once you internalise it you stop noticing.
The infinite loop
Drop the condition too and you have an infinite loop. This is the only way to write one in Go:
for {
// runs forever unless something breaks out
}
You exit an infinite loop from inside the body with break, return, or a runtime panic:
count := 0
for {
count++
if count >= 3 {
break
}
}
fmt.Println(count) // 3
This is the shape you reach for when the exit condition is decided inside the loop body: event loops, retry loops, server accept loops. break and continue are covered in the next section, and they work here too.
break and continue
break exits the enclosing loop entirely. continue skips the rest of the current iteration and moves on to the next one:
for i := 0; i < 10; i++ {
if i == 5 {
break // stop the loop completely
}
if i%2 == 1 {
continue // skip odd numbers and jump to i++
}
fmt.Println(i)
}
// prints 0, 2, 4
Both keywords act on the innermost enclosing loop by default. If you have nested loops and need to break out of the outer one, labelled break and continue solve that problem, covered later in this chapter.
- Use the three-part form when you have a natural counter: an index over a known range, a countdown, a stepper.
- Use the condition-only form when you are looping until some state changes: doubling until a value crosses a threshold, retrying until something succeeds, waiting until a condition flips.
- Use the infinite form when the exit condition is decided inside the loop body, and reach for
breakorreturnto stop.
The starter declares n := 0. Write two loops, one of each of the first two forms:
- A classic three-part
forthat prints each number from1to5(inclusive) on its own line. - A condition-only
forthat starts withn = 1and keeps doublingnwhilen < 50. After the loop, print the final value ofn.
1 2 3 4 5 64