GGistDev

for in Go

Go has one loop: for. It covers classic, while-like, range, and infinite loops. Prefer range for readability; fall back to index loops when mutating slices.

Classic for

The C-style three-part header: init; condition; post. All parts are optional; declare the index inside the loop scope.

for i := 0; i < 3; i++ {
    // ...
}

While-like

for i < n { /* ... */ }

Common for polling and read loops; ensure termination conditions to avoid infinite loops.

Infinite loop

for {
    // break when done
    if done { break }
}

Use with select in goroutines for servers and workers; always include a break/return path.

Range over collections

range iterates over elements of a variety of types, yielding index/key and value.

// slice
for i, v := range []int{10,20,30} { _ = i; _ = v }

// array
arr := [3]string{"a","b","c"}
for i, v := range arr { _ = i; _ = v }

// map (order not guaranteed)
m := map[string]int{"a":1, "b":2}
for k, v := range m { _ = k; _ = v }

// string (iterates runes)
for i, r := range "héllo" { _ = i; _ = r }

Notes:

  • On slices/arrays, v is a copy of the element; taking &v points to the loop variable, not the backing element
  • On maps, iteration order is randomized; don’t rely on it
  • On strings, i is byte offset and r is a rune (Unicode code point)

Control flow

for i := 0; i < 10; i++ {
    if i%2 == 0 { continue }
    if i > 7 { break }
}

Labels allow breaking/continuing outer loops; use sparingly for clarity.

Labels (advanced)

Outer:
for i := 0; i < 3; i++ {
    for j := 0; j < 3; j++ {
        if i == j { continue Outer }
        if i+j > 3 { break Outer }
    }
}

Pitfalls

  • Range over slice/map returns copies of values; if you need addresses, take care
  • Modifying a slice while ranging may skip/duplicate elements; usually range over indices
  • Map iteration order is random by design; do not rely on it
  • Capturing loop variables in goroutines: pass v as a parameter to avoid sharing the same variable

Patterns

// Range over indices (safe if mutating slice)
s := []int{1,2,3}
for i := range s {
    s[i] *= 2
}

// Accumulate
sum := 0
for _, v := range s { sum += v }

// Find
idx := -1
for i, v := range s { if v == 4 { idx = i; break } }

Summary

  • One looping construct, many forms
  • Prefer range for readability; use indices when mutating
  • Use labels sparingly; keep loops simple and clear
  • Be careful with addresses of range variables and goroutine captures