Go/
Lesson

Go has one loop keyword. When you ask AI to convert a Python while loop or a JavaScript forEach, it all becomes for. That simplicity is a feature, but it means AI has to pick the right for variant -- and it often picks wrong.

The four forms of for

Every for loop in Go is one of these. When AI generates a loop, your first job is identifying which form it used and whether it picked the right one.

FormSyntaxWhen to useAI mistake to watch for
Classicfor i := 0; i < n; i++Need a counterUsing i <= n causing off-by-one
While-stylefor conditionUnknown iteration countAdding unnecessary semicolons: for ; condition ;
Infinitefor { }Server loops, event loopsMissing break, creating actual infinite loops
Rangefor i, v := range collectionIterating collectionsIgnoring index when it matters, or vice versa
02

Classic three-part loop

When you ask AI to "iterate 10 times" or "loop from 0 to n", it generates this:

for i := 0; i < 5; i++ {
    fmt.Println("Iteration:", i)
}

The three parts: init; condition; post. All optional, but if you include any, you need the semicolons.

AI pitfall
AI frequently generates for i := 0; i <= len(items); i++ instead of i < len(items). That <= causes an index-out-of-bounds panic on the last iteration. Always check the comparison operator when reviewing AI loops.
03

While-style loops

Drop the init and post, and for becomes a while loop:

count := 0
for count < 3 {
    fmt.Println("Count is:", count)
    count++
}

No semicolons needed. AI trained on C-style languages sometimes generates for (; count < 3; ) which compiles but is not idiomatic Go. If you see semicolons in a condition-only loop, that is a code smellWhat is code smell?A pattern in code that isn't a bug but signals a design problem that will make future changes harder..

04

Infinite loops and break

When you ask AI to build a server listener or a retry loop, it generates this pattern:

for {
    conn, err := listener.Accept()
    if err != nil {
        break
    }
    go handleConnection(conn)
}

No condition means "loop forever." The only exit is break, return, or os.Exit.

AI pitfall
AI sometimes generates infinite loops that forget the exit condition entirely. When you see for { } in AI output, immediately scan for how it terminates. If there is no break, return, or channel receive that blocks, you have a CPU-burning infinite loop.
05

Range loops

This is where AI makes the most mistakes. range returns two values, and the rules change depending on what you are ranging over:

// Slices: index, value
fruits := []string{"apple", "banana", "cherry"}
for index, fruit := range fruits {
    fmt.Printf("%d: %s\n", index, fruit)
}

// Maps: key, value
ages := map[string]int{"Alice": 30, "Bob": 25}
for name, age := range ages {
    fmt.Printf("%s is %d\n", name, age)
}

// Strings: byte index, rune (not byte!)
for i, char := range "Go!" {
    fmt.Printf("Index %d: %c\n", i, char)
}

Do not need the indexWhat is index?A data structure the database maintains alongside a table so it can find rows by specific columns quickly instead of scanning everything.? Use blank identifier:

for _, fruit := range fruits {
    fmt.Println(fruit)
}

Do not need the value? Just omit it:

for i := range fruits {
    fmt.Println(i) // prints 0, 1, 2
}

What range returns by type

CollectionFirst valueSecond valueGotcha
Slice/Arrayindex (int)element copyModifying v does not modify the slice
Mapkeyvalue copyIteration order is randomized
Stringbyte indexrune (int32)Index skips for multi-byte characters
Channelreceived value(none)Blocks until channel closes
AI pitfall
AI regularly generates for _, v := range mySlice and then tries to modify v expecting it to change the original slice. It will not. v is a copy. To modify in place, use the index: mySlice[i] = newValue. This is one of the most common Go bugs AI produces.
06

Map iteration order is random

This trips up AI-generated tests constantly:

m := map[string]int{"a": 1, "b": 2, "c": 3}
for k, v := range m {
    fmt.Println(k, v) // Different order each run!
}

Go randomizes map iteration order on purpose. If AI generates a test that asserts keys[0] == "a" after ranging over a map, that test will pass sometimes and fail other times. This is a flaky test, and AI generates them regularly.

07

Labels for nested loops

When you need to break out of an outer loop from inside an inner one:

OuterLoop:
for i, a := range numbers {
    for _, b := range numbers[i+1:] {
        if a+b == 10 {
            fmt.Printf("Found: %d + %d = 10\n", a, b)
            break OuterLoop
        }
    }
}

Without the label, break only exits the inner loop. AI rarely generates labeled breaks, so if you need one, you will likely have to ask for it explicitly.

08

break and continue

for i := 0; i < 10; i++ {
    if i == 3 {
        continue // skip 3
    }
    if i == 7 {
        break // stop at 7
    }
    fmt.Println(i) // prints 0, 1, 2, 4, 5, 6
}
Good to know
i++ and i-- are statements in Go, not expressions. You cannot write j := i++ like in C. The compiler will reject it. AI trained on C/JavaScript sometimes generates this pattern.
09

Common patterns AI generates

Iterate backwards:

for i := len(items) - 1; i >= 0; i-- {
    fmt.Println(items[i])
}

Filter and collect:

var result []int
for _, v := range numbers {
    if v > 10 {
        result = append(result, v)
    }
}

Retry with backoff (AI loves this one):

for attempt := 0; attempt < maxRetries; attempt++ {
    err := doSomething()
    if err == nil {
        break
    }
    time.Sleep(time.Second * time.Duration(attempt+1))
}

AI pitfall
In the retry pattern above, AI sometimes forgets to check the final error after the loop exits. If all retries fail, the code silently continues. Always verify: does the AI handle the "all retries exhausted" case?