Loops
Go has one looping construct: for.
Introduction
Go has one looping construct: for. It replaces while, do-while, and traditional for loops from other languages. Go 1.22 fixed the loop variable capture bug — each iteration now gets a fresh variable in range loops, eliminating a classic goroutine closure trap.
Range iterates over slices, arrays, maps, strings, and channels. Understanding when to use index vs value, iterating maps in random order, and break/continue with labeled loops builds the iteration skills needed for data processing pipelines and batch jobs.
This lesson covers infinite loops, nested loops, and the range-over-int feature added in Go 1.22 for simple counter loops without manual increment boilerplate.
The story
A Prometheus exporter scrapes hundreds of pod metrics from a Kubernetes cluster every 15 seconds. A for loop walks the pod list, a range loop iterates label key-value pairs, and break stops early when a critical alert threshold fires — loops are the engine behind every observability pipeline at scale.
Both C-style for and for range appear in ETL jobs that transform CloudWatch logs into billing reports for AWS customers.
Understanding the topic
Key concepts
- for init; cond; post { } — C-style three-component loop.
- for cond { } — while-style loop.
- for { } — infinite loop; break to exit.
- for i, v := range slice — index and value; i or v can be _ to ignore.
- Go 1.22: for i := range n iterates 0 to n-1.
- break and continue support labels: break Outer for nested loops.
flowchart TDInit[Initialize] --> Cond{Condition?}Cond -->|true| Body[Loop Body]Body --> Update[Increment]Update --> CondCond -->|false| Exit([Exit])
Step-by-step explanation
- Init runs once; condition checked before each iteration; post runs after body.
- Range on slice returns index and copy of element (for struct, copy not reference).
- Range on map returns key, value in random order — don't depend on order.
- Range on channel receives until channel closed.
- break exits innermost loop; labeled break exits specified outer loop.
- continue skips to next iteration.
Practical code example
Processing a batch of transactions with range and labeled break:
package mainimport "fmt"type Transaction struct {ID intAmount float64Valid bool}func processBatch(txs []Transaction) (processed int, total float64) {Outer:for i, tx := range txs {if !tx.Valid {continue}if tx.Amount < 0 {fmt.Printf("invalid amount at index %d, stopping batch\n", i)break Outer}total += tx.Amountprocessed++}return}func main() {txs := []Transaction{{1, 100, true}, {2, 50, true}, {3, -10, true}, {4, 200, true},}n, sum := processBatch(txs)fmt.Printf("processed=%d total=%.2f\n", n, sum)for i := range 3 { // Go 1.22+fmt.Printf("tick %d\n", i)}}
Output
invalid amount at index 2, stopping batch processed=2 total=150.00 tick 0 tick 1 tick 2
Line-by-line code explanation
for i := 0; i < len(pods); i++is the classic indexed loop when you need position.for _, pod := range podsiterates values while discarding the index with_.for key, val := range pod.Labelswalks map entries — order is randomized by design.for { ... }creates an infinite loop — common in servers untilbreakorreturn.if pod.Status == "Failed" { break }exits the loop early on a critical condition.continueskips to the next iteration when a pod is not ready yet.for i := range 10(Go 1.22+) loops integers 0 through 9 without manual increment.sum += pod.CPUmaccumulates a total inside the loop body.
Key takeaway: Go 1.22 per-iteration loop vars fix goroutine bugs. Use labeled break sparingly — extract function often clearer.
Real-world use
Where you'll use this in production
- Batch processing records from database query results.
- Retry loops with exponential backoff in HTTP clients.
- Worker pools consuming from channels in for-range.
- Parsing and transforming CSV/JSON array elements.
Best practices
- Use for range as default iteration style.
- Modify slice elements by index: slice[i].Field = val (range value is copy).
- Extract loop body to function when loop exceeds ~15 lines.
- Use for i := range n (Go 1.22+) for simple counters.
- Avoid modifying map while ranging — undefined behavior.
- Prefer slices over indexed loops when functional style fits.
Common mistakes
- Taking address of range variable in goroutine pre-1.22 — fixed but know the history.
- Modifying map during range — can panic or skip entries.
- Assuming map iteration order — random by design.
- Off-by-one with manual for loops when range suffices.
- Infinite loop without break condition or context cancellation.
Advanced interview questions
Q1BeginnerHow many loop types does Go have?
Q2Beginnercontinue vs break?
Q3IntermediateRange over slice — value or reference?
Q4IntermediateBreak out of nested loops?
Q5AdvancedPaginated API fetch until no more pages without loading all.
Summary
for is Go's only loop — flexible as for, while, and infinite. range iterates slices, maps, strings, channels; Go 1.22 adds range n. Modify slice elements by index; range value is a copy. Use labeled break/continue or extract functions for nested control. Next lesson: functions, parameters, and variadic args.