Loops (for)
Master Go's single for loop — covering C-style, while-style, infinite, and range loops — plus break and continue.
On this page 13 sections
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
whilekeyword — Go only hasfor; drop the init/post clauses to get while-loop behavior. - Forgetting that an infinite
for {}loop needs an explicitbreakorreturnsomewhere, or it will never end. - Ignoring the range loop's index/value order — it's always index (or key) first, value second.
- Using
breakinside a nested loop expecting it to exit the outer loop — it only exits the innermost one unless you use a label.
Best Practices
- Use
rangewhenever 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).
rangeis the idiomatic way to iterate over slices, arrays, strings, and maps.breakexits a loop early;continueskips 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.