Arrays vs slices as values: what does this print?
Question 33HardGo 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()
sl := []int{1, 2, 3}
for i, v := range sl {
if i == 0 {
sl[1] = 100
}
fmt.Print(v, " ")
}
fmt.Println()
modify := func(a [3]int) { a[0] = 99 } // gets a copy of the array
modify(arr)
fmt.Println(arr[0])
Output:
1 2 3
1 100 3
1
Arrays are values. Assigning an array, passing it to a function, or using it as a range expression copies all of its elements. range arr evaluates the range expression once and loops over a copy, so the change to arr[1] is not seen. A slice is a small header (pointer, length, capacity). Copying the header shares the backing array, so the loop sees the new value. If you write range &arr or range arr[:], the array loop sees changes too, and you avoid the copy.
What follows from this:
- Large arrays in function parameters are expensive to copy. Pass a pointer or a slice.
- Arrays are comparable and can be map keys. Slices can't.
lenof an array is a compile-time constant.- In
for i, v := range, thevis always a copy of the element. Changingvnever updates the collection. Writes[i].field = xinstead.
More on Language Fundamentals & Types
- Q31Why is an interface holding a nil pointer not equal to nil? What does this print?
- Q32What is the difference between a defined type (
type A B) and an alias (type A = B)? - Q34How does Go handle integer overflow, division, and conversions between numeric types?
- Q35How did loop variable semantics change in Go 1.22, and what does this print?
- Q36How do range-over-func iterators (Go 1.23) work? What does this print?
- Q37How do struct field alignment and padding work? What are the sizes of these structs?