Go

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.
  • len of an array is a compile-time constant.
  • In for i, v := range, the v is always a copy of the element. Changing v never updates the collection. Write s[i].field = x instead.

More on Language Fundamentals & Types

All 39 Language Fundamentals & Types questions