Loops and Iteration

Updated

July 30, 2026

Overview

Go has only one looping construct: the for loop. This single keyword handles all looping patterns.

The Basic for Loop

for i := 0; i < 10; i++ {
    fmt.Println(i)
}

The while Loop (Condition Only)

n := 1
for n < 100 {
    n *= 2
}

The Infinite Loop

for {
    if done {
        break
    }
}

The range Loop

Slices and Arrays

nums := []int{10, 20, 30}

for i, v := range nums {
    fmt.Printf("%d: %d\n", i, v)
}

for _, v := range nums {  // Value only
    fmt.Println(v)
}

Maps

ages := map[string]int{"Alice": 30, "Bob": 25}

for key, value := range ages {
    fmt.Printf("%s: %d\n", key, value)
}

Strings

for i, r := range "Hello" {
    fmt.Printf("%d: %c\n", i, r)
}

Channels

for v := range ch {  // Exits when channel closes
    fmt.Println(v)
}

Iterators (Go 1.23+)

Go 1.23 introduced “range-over-func,” allowing you to use range with custom iterator functions.

Sequence Iterators

A sequence iterator is a function that takes a yield function: func(yield func(V) bool) (single value) or func(yield func(K, V) bool) (key-value).

func All[T any](s []T) iter.Seq[T] {
    return func(yield func(T) bool) {
        for _, v := range s {
            if !yield(v) {
                return
            }
        }
    }
}

// Usage
for v := range All(nums) {
    fmt.Println(v)
}

Pull Iterators

For more control, you can use pull iterators:

next, stop := iter.Pull(All(nums))
defer stop()

for {
    v, ok := next()
    if !ok {
        break
    }
    fmt.Println(v)
}

Loop Control

break and continue

for i := 0; i < 10; i++ {
    if i == 5 {
        break     // Exit loop
    }
    if i%2 == 0 {
        continue  // Skip to next iteration
    }
    fmt.Println(i)
}

Labels for Nested Loops

outer:
for i := 0; i < 3; i++ {
    for j := 0; j < 3; j++ {
        if i == 1 && j == 1 {
            break outer  // Break both loops
        }
    }
}

Common Patterns

// Reverse iteration
for i := len(items) - 1; i >= 0; i-- {
    process(items[i])
}

// Step by N
for i := 0; i < 100; i += 10 {
    fmt.Println(i)
}

Summary

Pattern Syntax
Classic for for i := 0; i < n; i++ {}
While loop for condition {}
Infinite loop for {}
Range for i, v := range slice {}
Iterators for v := range myIter() {}

More examples

Example: classic for and range

Save as main.go and go run . (with go mod init example if needed).

package main

import "fmt"

func main() {
    sum := 0
    for i := 1; i <= 4; i++ {
        sum += i
    }
    fmt.Println("sum:", sum)

    for i, v := range []string{"a", "b", "c"} {
        fmt.Printf("%d:%s ", i, v)
    }
    fmt.Println()
}

Expected:

sum: 10
0:a 1:b 2:c 

Example: break and continue

Save as main.go and go run . (with go mod init example if needed).

package main

import "fmt"

func main() {
    for i := 0; i < 6; i++ {
        if i%2 == 0 {
            continue
        }
        if i > 3 {
            break
        }
        fmt.Println("odd:", i)
    }
}

Expected:

odd: 1
odd: 3

Runnable example

Save as main.go. From an empty directory:

go mod init example
go run .
package main

import "fmt"

func main() {
    // Classic for
    sum := 0
    for i := 1; i <= 5; i++ {
        sum += i
    }
    fmt.Println("sum 1..5:", sum)

    // while-style
    n := 1
    for n < 100 {
        n *= 2
    }
    fmt.Println("first power of two >= 100:", n)

    // range over slice
    nums := []int{10, 20, 30}
    for i, v := range nums {
        fmt.Printf("slice[%d]=%d\n", i, v)
    }

    // range over map (order not guaranteed)
    ages := map[string]int{"Ada": 36, "Grace": 85}
    for name, age := range ages {
        fmt.Printf("%s is %d\n", name, age)
    }

    // range over string yields runes
    for i, r := range "Go🚀" {
        fmt.Printf("string index %d rune %c\n", i, r)
    }

    // break / continue / labeled break
    fmt.Print("odds < 5: ")
    for i := 0; i < 10; i++ {
        if i >= 5 {
            break
        }
        if i%2 == 0 {
            continue
        }
        fmt.Print(i, " ")
    }
    fmt.Println()

outer:
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            if i == 1 && j == 1 {
                fmt.Printf("breaking outer at i=%d j=%d\n", i, j)
                break outer
            }
        }
    }

    // reverse step
    for i := 4; i >= 0; i -= 2 {
        fmt.Println("reverse step:", i)
    }
}

Expected output (illustrative; map line order may vary):

sum 1..5: 15
first power of two >= 100: 128
slice[0]=10
slice[1]=20
slice[2]=30
Ada is 36
Grace is 85
string index 0 rune G
string index 1 rune o
string index 2 rune 🚀
odds < 5: 1 3 
breaking outer at i=1 j=1
reverse step: 4
reverse step: 2
reverse step: 0

What to notice: - One keyword (for) covers C-style, while-style, and infinite loops. - range adapts to slices, maps, and strings (byte index + rune). - continue / break and labels control nested loops cleanly. - Map iteration order is randomized—never rely on it.

Try next: Change the string to include combining characters or emoji and print both i and len("…").