Working with array in Go.
Array in Go is just a data structure that hold a collection of elements of any type. Each element can be accessed by its index. Length of array is fixed at compile time and its size is a part of its type.
The type [n]T is an array of n values of type T. It can be declared as full declaration statement or in a short-hand format, with or without init values.
Array also can be declared in form of [...]T where its size will be determined by the compiler.
var holidays = [7]bool{}
seasons := [4]string{"Spring", "Summer", "Autumn", "Winter"}
weekDays := [7]int{1, 2, 3, 4, 5, 6, 7}
fruits := [...]string{"apple", "guava", "orange"}
visited := [10]bool{1: true, 3: true, 5: true, 7: true, 9: true}
sudoku := [9][9]int{}
Size of array is a part of its type and it is determined at the compile time
That means you cannot extend its size at run-time and cannot assign it to another type at run-time:
fruits := [...]string{"apple", "guava", "orange"}
moreFruits := [4]string{"grapes"}
moreFruits = fruits
Arrays are comparable if they have same type
firstArr := [3]int{1, 2, 3}
secondArr := [3]int{1, 2, 3}
thirdArr := [4]int{1, 2, 3, 4}
fmt.Println(firstArr == secondArr)
fmt.Println(secondArr == thirdArr)
Each elements can be accessed by index or range over the array. Access index out of the array will cause a panic
var weekDays [7]string
weekDays[0] = "Sunday"
weekDays[1] = "Monday"
weekDays[2] = "Tuesday"
weekDays[3] = "Wednesday"
weekDays[4] = "Thursday"
weekDays[5] = "Friday"
weekDays[6] = "Saturday"
fmt.Println(weekDays[5])
fmt.Println("Days in a week:")
for _, day := range weekDays {
fmt.Printf("\t%s\n", day)
}
Passing an array to a method will create a copy of the original array
This means what you do with the copied array will not affect to the original array.
package main
import "fmt"
func main() {
fruits := [3]string{"apple", "orange"}
addGuava(fruits)
}
func addGuava(fruits [3]string) {
fruits[2] = "guava"
}
Playground
Passing the pointer of the array to a function if you want to change its value in that function:
package main
import "fmt"
func main() {
fruits := [3]string{"apple", "orange"}
addGuava(&fruits)
}
func addGuava(fruits *[3]string) {
fruits[2] = "guava"
}
Playground
Assign or range statement on an array will also create a copy of the original array
arr := [4]int{0, 1, 2, 3}
newArr := arr
fmt.Printf("%p != %p", &arr, &newArr)
Playground
Interact with value of array while ranging over it will not affect the original value:
arr := [4]int{0, 1, 2, 3}
for _, v := range arr {
v += 100
}
fmt.Println(arr)
Playground
If you want to change value of original array while ranging over it, use index instead:
arr := [4]int{0, 1, 2, 3}
for i := 0; i < len(arr); i++ {
arr[i] += 100
}
fmt.Println(arr)
Playground
Pointer of index and value inside range statement will be reused.
Notice that the pointers of i
and v
are the same in the result:
arr := [3]int{1, 2, 3}
for i, v := range arr {
fmt.Printf("i=%d, v=%d, &i=%p, &v: %p\n", i, v, &i, &v)
}
Playground
This will cause a problem if you use goroutine inside the for loop as below. Notice that only the last element is printed.
arr := [3]int{1, 2, 3}
for i, v := range arr {
go func() {
fmt.Printf("i=%d, v=%d, &i=%p, &v: %p\n", i, v, &i, &v)
}()
}
Playground
Define local variable to avoid the variables are captured is one way to avoid the above problem:
arr := [3]int{1, 2, 3}
for i, v := range arr {
i, v := i, v
go func() {
fmt.Printf("i=%d, v=%d, &i=%p, &v: %p\n", i, v, &i, &v)
}()
}
Playground
When do you use array?
Normally, array is used when the number of element is fixed at compile time. Example:
- Used in parsing network package where the length of the package is fixed. Example: TCP, UDP, DHCP, DNS packages, ...
- Used in hashing, encryption algorithms: MD5, Base64, Base58,...
- Represent a collection of fixed length elements like: days in a week, months in a year, ...