Go

Array vs slice in range: what prints?

Question 486HardGo 1.22 to 1.25
arr := [3]int{1, 2, 3}
for i, v := range arr {
    if i == 0 {
        arr[1] = 100
    }
    fmt.Print(v, " ")
}
fmt.Println(arr)

sl := []int{1, 2, 3}
for i, v := range sl {
    if i == 0 {
        sl[1] = 100
        sl = append(sl, 4)
    }
    fmt.Print(v, " ")
}
fmt.Println(sl)

Output:

1 2 3 [1 100 3]
1 100 3 [1 100 3 4]

The range expression is evaluated once, before the loop starts. For an array, the value is copied, so iteration reads the copy and never sees arr[1] = 100. Use range &arr or arr[:] to iterate the original without a copy.

For a slice, only the header is copied. The element write is visible because the backing array is shared, so the loop prints 100. The length is fixed at 3, though, so the appended element is never visited. Even if append had reallocated, the loop would keep reading the old array. Ranging over a large array value also copies the whole thing, which is a performance trap.

More on Tricky Output & Code-Review Puzzles

All 38 Tricky Output & Code-Review Puzzles questions