Loops (for)
Master Go's single for loop — covering C-style, while-style, infinite, and range loops — plus break and continue.
Introduction
Most languages give you several looping keywords — for, while, do-while, foreach. Go simplifies this down to a single keyword, `for`, that flexibly covers every one of those styles. Once you understand its variations, you have everything you need to loop over anything in Go.
Why Go Has Only One Loop Keyword
True to its philosophy of "one way to do things," Go deliberately has no separate `while` or `do-while` keyword. The single `for` keyword adapts based on what you put in its header — a full three-part clause, a single condition, nothing at all, or a `range` clause — covering every loop style other languages need multiple keywords for.
The C-Style for Loop
The most familiar form has three parts separated by semicolons: an initialization statement, a condition, and a post statement — exactly like C, Java, or JavaScript.
package main
import "fmt"
func main() { for i := 0; i < 5; i++ { fmt.Println("Iteration:", i) }}Click Run to see what this code prints.
The while-Style Loop
Drop the initialization and post statements, keeping only a condition, and `for` behaves exactly like a `while` loop in other languages.
package main
import "fmt"
func main() { count := 3
for count > 0 { fmt.Println("Countdown:", count) count-- } fmt.Println("Liftoff!")}Click Run to see what this code prints.
The Infinite Loop
Omit the condition entirely and `for` loops forever, until something inside the loop body explicitly stops it with `break` or `return`.
package main
import "fmt"
func main() { n := 0
for { if n == 3 { break } fmt.Println("n is", n) n++ }}Click Run to see what this code prints.
The range Loop
The `range` clause iterates over elements of a slice, array, string, or map, giving you the index (or key) and the value on each pass. It's the idiomatic way to loop over a collection in Go.
package main
import "fmt"
func main() { fruits := []string{"apple", "banana", "cherry"}
for index, fruit := range fruits { fmt.Println(index, fruit) }
// If you only need the value, discard the index with _ for _, fruit := range fruits { fmt.Println("I like", fruit) }}Click Run to see what this code prints.
break and continue
`break` immediately exits the innermost loop. `continue` skips the rest of the current iteration and moves on to the next one.
package main
import "fmt"
func main() { for i := 1; i <= 10; i++ { if i%2 != 0 { continue // skip odd numbers } if i > 6 { break // stop once we pass 6 } fmt.Println(i) }}Click Run to see what this code prints.
Labeled break and continue
When loops are nested, a plain `break` or `continue` only affects the innermost loop. To control an outer loop from inside a nested one, use a label.
package main
import "fmt"
func main() {outer: for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { if j == 1 { continue outer } fmt.Println(i, j) } }}Click Run to see what this code prints.
Here, `continue outer` skips straight to the next iteration of the outer loop as soon as `j` reaches 1, rather than just skipping the rest of the inner loop.
Common Mistakes
- Looking for a separate `while` keyword — Go only has `for`; drop the init/post clauses to get while-loop behavior.
- Forgetting that an infinite `for {}` loop needs an explicit `break` or `return` somewhere, or it will never end.
- Ignoring the range loop's index/value order — it's always index (or key) first, value second.
- Using `break` inside a nested loop expecting it to exit the outer loop — it only exits the innermost one unless you use a label.
Best Practices
- Use `range` whenever iterating over a slice, array, string, or map — it's more idiomatic and less error-prone than manual indexing.
- Discard unused range variables with `_` rather than leaving unused variables around.
- Reserve labeled break/continue for genuinely nested-loop situations; overusing labels can hurt readability.
- Prefer the while-style `for condition {}` over an infinite loop with an immediate break check, when a simple condition will do.
Frequently Asked Questions
Not as a dedicated keyword, but you can simulate one using an infinite for loop with a break condition checked at the end of the body.
range over a map yields key and value pairs on each iteration, though the iteration order of a map is not guaranteed to be consistent between runs.
Use `for i := 0; i < n; i++` and simply not reference i inside the body, or use `for range n` (Go 1.22+) to loop n times without needing an explicit counter variable.
Key Takeaways
- Go has a single loop keyword, `for`, that covers C-style, while-style, infinite, and range loops.
- Omitting parts of the for header changes its behavior: full three clauses (C-style), condition only (while-style), nothing (infinite).
- `range` is the idiomatic way to iterate over slices, arrays, strings, and maps.
- `break` exits a loop early; `continue` skips to the next iteration.
- Labels let break/continue target an outer loop from within nested loops.
Summary
You've now mastered every style of Go's single, flexible for loop, along with break, continue, and labeled loop control. Next, you'll learn how switch statements offer a cleaner alternative to long else-if chains for multi-way branching.