Loops
Go has one loop keyword: for. There's no while,
no do…while, no repeat. The single for
just wears four different hats depending on how you use it.
Learning objectives
- Recognize all four forms of
for: three-part, condition-only, infinite, and range. - Use
breakandcontinue(and labels) effectively. - Iterate over slices, maps, strings, channels, and (in Go 1.22+) integers.
- Avoid the classic loop-variable-in-closure pitfall.
Classic three-part for
for i := 0; i < 5; i++ {
fmt.Println(i)
}
Three pieces separated by semicolons:
- Init: runs once before the loop.
- Condition: checked before each iteration.
falseends the loop. - Post: runs after each iteration.
Any of the three can be omitted.
While equivalent
Drop init and post, keep only the condition:
i := 0
for i < 5 {
fmt.Println(i)
i++
}
This is how you write a "while" in Go.
Infinite loops
Drop the condition entirely:
for {
// runs forever until break or return
}
Idiomatic for servers, poll loops, and goroutines that run for the
program's lifetime. You exit with break, return,
or by letting the process end.
break & continue
package main
import "fmt"
func main() {
for i := 0; i < 10; i++ {
if i == 5 {
break // exits the loop
}
if i%2 == 0 {
continue // skips to the next iteration
}
fmt.Println(i)
}
}
This prints 1 and 3. When i
reaches 5, break exits the loop entirely.
range
range iterates over almost every built-in sequence. It
yields index + value for ordered containers, and
key + value for maps.
Slices & arrays
nums := []int{10, 20, 30}
for i, v := range nums {
fmt.Println(i, v)
}
Maps (random order!)
ages := map[string]int{"Alice": 30, "Bob": 25}
for name, age := range ages {
fmt.Println(name, age)
}
Strings (rune-aware)
for i, r := range "café" {
fmt.Printf("byte %d = %q\n", i, r)
}
See Chapter 7: range over a string yields runes, not bytes.
Channels
for v := range ch {
fmt.Println(v) // ends when the channel is closed
}
More on channels in Chapter 25.
Discarding the index or value
for _, v := range nums { ... } // only values
for i := range nums { ... } // only indexes (omit the comma)
for range nums { ... } // just iterate (Go 1.4+)
range over an int (Go 1.22+)
Since Go 1.22, you can range over an integer literally, a cleaner way to run a fixed number of iterations:
for i := range 5 {
fmt.Println(i) // 0, 1, 2, 3, 4
}
Equivalent to for i := 0; i < 5; i++ but shorter.
Nested & labeled loops
To break out of an outer loop from within an inner one, use a label:
package main
import "fmt"
func main() {
matrix := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
outer:
for i, row := range matrix {
for j, v := range row {
if v == 5 {
fmt.Println("found at", i, j)
break outer // breaks the OUTER loop
}
}
}
}
The label goes on its own line, ending with a colon, just before the
loop it names. continue LABEL works the same way.
Common patterns & pitfalls
Classic loop-variable-in-closure (fixed in Go 1.22)
// In Go 1.21 and earlier, this prints "3 3 3", surprise!
// In Go 1.22+, it prints "0 1 2", per-iteration variables.
for i := 0; i < 3; i++ {
go func() {
fmt.Println(i)
}()
}
i := i inside the loop body, then use that.
Do-while pattern
Go has no do-while. Reach for an infinite loop with a conditional break:
for {
answer := prompt()
if isValid(answer) {
break
}
}
Countdown
for i := 5; i > 0; i-- {
fmt.Println(i)
}
fmt.Println("lift-off!")
Check your understanding
Practice exercises
Sum of squares
Write a program that computes the sum of squares from 1 to 10 (that
is, 1² + 2² + 3² + … + 10²). Print the result.
Show one possible solution
package main
import "fmt"
func main() {
sum := 0
for i := 1; i <= 10; i++ {
sum += i * i
}
fmt.Println(sum) // 385
}
Stable map iteration
Given a map[string]int, print its entries sorted by
key. Use sort.Strings from the sort
package.
Show one possible solution
package main
import (
"fmt"
"sort"
)
func main() {
m := map[string]int{
"cherry": 3, "apple": 1, "banana": 2,
}
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Printf("%s = %d\n", k, m[k])
}
}
This is the idiomatic way to get deterministic output from a map.
Further reading
One keyword, every shape of loop.