Slices in Go
| Make a slice | |
| Append grows it | |
| Len vs cap | |
| Slicing a slice |
Make a slice
A slice is a flexible view over a backing array: it can grow, and it passes around cheaply because only a small header is copied. Build one with a literal, or with make when you know the starting length.
package main
import "fmt"
func main() {
nums := []int{1, 2, 3}
fmt.Println(nums)
names := make([]string, 2)
names[0] = "Ada"
fmt.Println(names)
}
go run main.go
[1 2 3]
[Ada ]
Notice the missing length in []int: that empty bracket pair is exactly what tells Go you want a slice and not an array. Make with two arguments sets length and capacity together; the optional third argument reserves extra room for growth without reallocation.
Append grows it
Append returns a slice with new elements added at the end, and you must store the result back because growth can move the data to a larger array. Appending is the everyday way slices grow.
package main
import "fmt"
func main() {
nums := []int{1, 2}
nums = append(nums, 3, 4)
fmt.Println(nums)
}
[1 2 3 4]
Forgetting the assignment back is the classic beginner bug: the append happens, but the old variable still points at the short slice. Always write nums equals append of nums to keep the grown result.
Len vs cap
Len reports how many elements the slice holds right now, while cap reports how many fit before the next growth step must allocate. Watching both explains why some appends feel free and others copy.
package main
import "fmt"
func main() {
s := make([]int, 2, 5)
fmt.Println(len(s), cap(s))
s = append(s, 1, 2, 3)
fmt.Println(len(s), cap(s))
}
2 5
5 5
Capacity is a performance detail, not a limit: append past it and Go allocates a bigger array automatically. Pre sizing with make avoids repeated copying when the final size is known in advance.
Slicing a slice
Cut a new slice out of an old one with low:high bounds, where low is included and high is excluded. The result shares the same backing array, so it starts as a window rather than a copy.
package main
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5}
mid := nums[1:4]
mid[0] = 9
fmt.Println(nums)
}
[1 9 3 4 5]
Sharing cuts allocations but also surprises: writing through one slice shows up in the other. Copy with the builtin copy function when the new slice must live its own life.
Next: Maps
Article author: Arthur Isaev