Arrays are mutable
Strings in Go are immutable: you cannot change one character of a string in place. Arrays are different. Each element is a variable you can assign to at any time, using the same index notation you use to read it:
ourArray := [3]int{50, 40, 30}
ourArray[0] = 15
ourArray[1] = -1
fmt.Println(ourArray)
[15 -1 30]
Only the elements you assign to change. ourArray[2] is still 30. The array keeps its length of 3, because the length is part of its type and can never change.
Strings cannot be updated this way
The contrast with strings is worth seeing once. Reading s[0] from a string gives a byte, but assigning to it does not compile:
s := "cat"
s[0] = 'b' // compile error: cannot assign to s[0]
To change a string you build a new one, for example by converting it to a []byte, changing that, and converting back. Arrays need none of this.
The value must match the element type
Every element of an array has the same type, and an assignment has to respect it. Putting a number into a [3]string is a compile error. Go reports that it cannot use 5 as a string value:
fruits := [3]string{"mango", "kiwi", "grapefruit"}
fruits[0] = 5 // compile error
Updating from the current value
Often the new value depends on the old one. You can write it out in full, or use a compound assignment operator:
ages := [4]int{14, 32, 50, 21}
ages[1] = ages[1] + 5
ages[1] += 5
ages[2]++
fmt.Println(ages)
[14 42 51 21]
The first two assignments each add 5 to the second element, so it goes from 32 to 37 and then to 42. The ++ statement adds 1 to the third. In Go, ++ and -- are statements, not expressions, so you cannot write x := ages[2]++.
The exercise
The lesson starts with two arrays:
fruits := [3]string{"mango", "kiwi", "grapefruit"}
ages := [4]int{14, 32, 50, 21}
It asks for two updates:
- Replace the first fruit with
"apple". The first item is at index 0, so assign tofruits[0]. - Add 5 to the second age. The second item is at index 1, and
+=reads the old value, adds 5 and writes the sum back.
fruits[0] = "apple"
ages[1] += 5
After these lines fruits holds apple, kiwi and grapefruit, and ages holds 14, 37, 50 and 21.
Updating every element
A loop that produces the index lets you update all the elements with one line of code. Here each age is doubled in place:
for i := 0; i < len(ages); i++ {
ages[i] *= 2
}
fmt.Println(ages)
[28 64 100 42]
The assignment goes through ages[i], which names the element itself. That is why this works. A loop variable that merely receives a copy of each value could not update the array.
Arrays are copied when passed around
An array is a value. When you pass it to a function, the function receives its own copy, so updating the copy does not touch the original:
func change(a [3]int) { a[0] = 999 }
change(ourArray)
fmt.Println(ourArray)
[15 -1 30]
To let a function update the caller's array, pass a pointer, *[3]int, and call it with &ourArray. Slices, which the next lessons cover, behave differently.
Common mistakes
- Using a wrong index. The first item is index 0. Assigning to
fruits[1]changeskiwi. - Assigning outside the array.
ages[4] = 1on a four-element array is a compile error, and an array never grows. - Mixing types. Assigning a string to an element of an
[4]int, or a number to an element of a[3]string, is rejected by the compiler before the program runs, so these mistakes are cheap to find. - Expecting a function to change your array. The function gets a copy unless you pass a pointer.
Key takeaways
- Assign to an element with
array[i] = value; only that element changes. - The value must have the element type, and the array's length stays fixed.
+=,-=and++update an element from its current value.- Arrays are copied when assigned or passed, so a function changes its own copy.