Introduction
Control flow determines which code runs and how many times. Go simplifies this by having just one looping construct (for) that handles all iteration patterns. Combined with if/else branching, you have everything needed to express complex logic clearly.
Key Concepts
For Loop: Go's only loop construct, versatile enough to replace while, do-while, and traditional for loops from other languages.
If Statement: Conditional execution with optional initialization statement.
Scoped Variables: Variables declared in the if initialization are scoped to the entire if-else chain.
Break/Continue: Control statements for exiting loops or skipping iterations.
Real World Context
Having a single loop construct means every Go developer reads loops the same way—no debates about when to use while vs for. The if-with-initialization pattern is heavily used for error checking (if err := doThing(); err != nil), creating a clean pattern that keeps error handling variables scoped appropriately.
Deep Dive
For Loop Variants
go// Classic three-component for i := 0; i < 10; i++ { fmt.Println(i) } // While-style (condition only) n := 0 for n < 5 { n++ } // Infinite loop for { if shouldStop() { break } } // Range over collections nums := []int{1, 2, 3} for index, value := range nums { fmt.Println(index, value) } // Range over string (iterates runes) for i, r := range "Hello" { fmt.Printf("%d: %c\n", i, r) }
If Statements
go// Simple if if x > 0 { return "positive" } // If with initialization (very common pattern) if err := process(); err != nil { return err } // If-else chain if x < 0 { return "negative" } else if x == 0 { return "zero" } else { return "positive" }
Loop Control
gofor i := 0; i < 10; i++ { if i == 3 { continue // Skip this iteration } if i == 7 { break // Exit the loop } }
Common Pitfalls
-
Forgetting the blank identifier: When ranging, if you only need the value, use
for _, v := range items. Unused variables cause compile errors. -
Modifying slice during range: The range expression is evaluated once. Adding/removing elements during iteration can cause unexpected behavior.
-
Variable shadowing in if initialization:
if x := compute(); x > 0creates a newxthat shadows any outerxvariable.
Best Practices
- Use
for rangefor iterating over slices, maps, and strings. - Use the if-initialization pattern for error handling.
- Prefer early returns over deeply nested else blocks.
- Use
breakandcontinuewith labeled loops for complex nested scenarios.
Summary
Go uses for as its only loop keyword, supporting classic, while-style, infinite, and range-based iteration. If statements can include an initialization clause, scoping variables to the conditional block. The break and continue keywords control loop execution.
Code Examples
package main
import "fmt"
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}