For Loops in Go
Go has exactly one looping construct — for — and it flexes to cover every loop shape other languages need separate keywords for.
3 min read
Most languages give you for, while, and do-while as separate keywords. Go gives you exactly one: for. It just changes shape depending on what you leave out.
The classic three-part for loop
for i := 0; i < 5; i++ {
fmt.Println(i)
}This is the familiar init/condition/post form: i := 0 runs once, i < 5 is checked before each iteration, and i++ runs after each iteration. No parentheses around the clauses, mandatory braces — same rules as if.
for as a while loop
Drop the init and post clauses and for behaves exactly like while in other languages:
count := 0
for count < 5 {
fmt.Println(count)
count++
}for as an infinite loop
Drop the condition entirely and you get an infinite loop, which you break out of explicitly:
i := 0
for {
if i >= 5 {
break
}
fmt.Println(i)
i++
}This shape is common for server loops, worker loops, and anywhere the exit condition is more naturally expressed inside the body than in a single boolean up front.
Looping over collections with range
For iterating over arrays, slices, maps, strings, or channels, range is what you'll use almost always:
fruits := []string{"apple", "banana", "cherry"}
for index, fruit := range fruits {
fmt.Println(index, fruit)
}range yields two values on each iteration: the index (or map key) and the value. If you don't need the index, discard it with the blank identifier:
for _, fruit := range fruits {
fmt.Println(fruit)
}If you only want the index, just drop the second variable entirely:
for index := range fruits {
fmt.Println(index)
}Ranging over a map gives you key and value:
ages := map[string]int{"Ada": 32, "Grace": 45}
for name, age := range ages {
fmt.Println(name, "is", age)
}Note that map iteration order in Go is intentionally randomized on each run — this is a deliberate design decision to stop code from accidentally depending on an order the language never promised.
break and continue
Both work as you'd expect from other languages:
for i := 0; i < 10; i++ {
if i == 3 {
continue // skip this iteration
}
if i == 6 {
break // exit the loop entirely
}
fmt.Println(i)
}Labeled loops
For breaking or continuing an outer loop from inside a nested one, Go supports labels — something few modern languages bother with:
outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if j == 1 {
continue outer
}
fmt.Println(i, j)
}
}Without the label, continue would only affect the innermost loop. This is a niche feature, but it's the cleanest way to escape deeply nested loops without a flag variable.
One for, four shapes, no separate while to remember — it's a small example of Go's broader philosophy of doing more with less syntax.
Test what you just learned
4 quick questions. Get all of them right to unlock the next lesson.
You can take the quiz without an account — logging in just lets your result count toward your progress.