Arrays in go operate like arrays in many other compiled languages. The size is built-in to the type, and to grow an array you must create a larger one and copy all the values.
...
func main() {
var x [4]int
var y [4]int = [4]int{1,2}
fmt.Println(x, y)
x[0] = 1
x[3] = 9
fmt.Println(x)
}- You declare an array by prepending the type with
[N]where N is the length of the array. - When the array
xwas declared, the memory of it was allocated and each entry was initialized to its zero-value. - You can get or set an element of an array by indexing into it (
x[0], for example). - You can assign to the whole (or partial, starting from the beginning) array by creating an array literal (ex.
[4]int{1,2,3}). - Unlike c, go will panic if you try to index outside of the array.
While arrays have the type [N]type, slices have the tye []type, allowing them to grow.
To create a slice with an initial length of zero:
...
func main() {
var x []int
fmt.Println(x)
x = append(x, 1)
x = append(x, 2)
x[0] = -1
fmt.Println(x)
}append only works for slices, not arrays.
Under the hood, a slice is a pointer to an array, a length, and a capacity. append will simply increase the length until it hits capacity, at which point it will make a new larger array and copy data to it.
To see the capacity, use the cap function.
To create slices with different lengths and capacity, use make.
...
func main() {
var x []int = make([]int, 4) // length = 4, (inferred capacity = 4)
y := make([]int, 4, 10) // length = 4, capacity = 10
fmt.Println(cap(x), cap(y))
x = append(x, 1)
y = append(y, 1)
fmt.Println(x, y)
}When do you want to use length?
- If you want to assign using indexes up to the length.
When do you want to use capacity?
- When you know around how large your slice will be and want to increase performance.
Maps have the type map[N]M where N is the key type, and M is the value type. There is no mixing types in go maps. Additionally, the zero-value of a map is nil, so maps must be initialized with make or a map literal to write to them.
...
func main() {
m := make(map[string]int) //empty map
n := map[string]int{
"books": 4,
"movies": 7,
}
m["shows"] = 4
fmt.Println(m, n)
}When you index into a map with a value that isn't present, it evaulates to the zero-value of the type. You can also check that the value exists:
...
func main() {
m := map[string]int {
"a": 1,
"b": 2,
}
c := m["c"]
fmt.Println(c)
d, ok := m["d"]
fmt.Println(d, ok)
}Now that we have arrays, slices, and maps, let's look at how we can iterate through them.
...
func main() {
x := [4]int{1, 2}
y := []int{3, 4, 5}
z := map[string]int{"a": 1, "b": 2}
for i, el := range x {
fmt.Println(i, el)
}
for i, el := range y {
fmt.Println(i, el)
}
for k, v := range z {
fmt.Println(k, v)
}
}You can also iterate through just the indices of the list or slice and keys of the map:
...
func main() {
...
for i := range x {
fmt.Println(i)
}
for k := range z {
fmt.Println(k)
}
}If you would like to iterate through just the values of a list or map, use _:
...
func main() {
...
for _, el := range x {
fmt.Println(el)
}
for _, val := range z {
fmt.Println val
}
}Create a slice of lists of maps.
Lists are used less frequently than slices. If you're having trouble deciding, use a slice.
If you're feeling adventurous, this is a great read on the implementation of golang (and C++ and Java) maps.