What does this print? (range over a nil pointer to an array, and range over an int)
Question 74HardGo 1.22 to 1.25
func main() {
var p *[3]int
fmt.Println(len(p))
for i := range p {
fmt.Print(i, " ")
}
fmt.Println()
for i := range 3 { // Go 1.22 range-over-int
fmt.Print(i, " ")
}
fmt.Println()
defer func() { fmt.Println("recovered:", recover()) }()
for i, v := range p {
fmt.Println(i, v)
}
}
Output:
3
0 1 2
0 1 2
recovered: runtime error: invalid memory address or nil pointer dereference
For an array or a pointer to an array, len(p) is a compile-time constant (3). The pointer is never dereferenced, so it works even when p is nil. The spec says the range expression is evaluated once, with one exception: when there is at most one iteration variable and len(x) is constant, the range expression is not evaluated at all. So for i := range p just counts 0 to 2.
With two variables, the loop must read p[i], which dereferences the nil pointer and panics.
for i := range n (Go 1.22) evaluates n once and loops from 0 to n-1. If n is 0 or negative, the loop body never runs. The type of i is the type of n. With an untyped constant, i is int.
More on Arrays, Slices, Maps & Strings
- Q72What does this print before and after Go 1.22? (taking &v and capturing i in loops)
- Q73What does this print? (map of slices built from a shared base)
- Q75How do range-over-func iterators work on slices and maps, and what happens if an iterator ignores yield's return value?
- Q76What is the unique package (Go 1.23), and how does it help with memory for repeated strings?