Go Slices
A slice is Go's flexible, dynamically-sized view over an underlying array, and it is the collection type you will reach for almost every day.
What Is a Slice
A slice is a lightweight struct containing a pointer to an underlying array, a length, and a capacity. Unlike an array, a slice's type does not encode a size — []int can hold zero elements or a million. Slices are created with a slice literal, by slicing an existing array or slice with the [low:high] syntax, or with the built-in make function.
Creating Slices
package main
import "fmt"
func main() {
fruits := []string{"apple", "banana", "cherry"}
fmt.Println(fruits)
numbers := make([]int, 3, 5)
numbers[0] = 10
fmt.Println(numbers, "len:", len(numbers), "cap:", cap(numbers))
sub := fruits[1:3]
fmt.Println(sub)
}Growing Slices with append
The append function adds one or more elements to the end of a slice and returns the resulting slice, which you must assign back to the original variable. When a slice's length would exceed its capacity, Go allocates a new, larger underlying array (typically doubling it) and copies the existing elements over automatically — you never manage this memory by hand.
Appending Elements
package main
import "fmt"
func main() {
var tasks []string
tasks = append(tasks, "write code")
tasks = append(tasks, "test code", "deploy code")
fmt.Println(tasks)
fmt.Println("len:", len(tasks), "cap:", cap(tasks))
}len() vs cap()
len() reports how many elements a slice currently holds, while cap() reports how many elements the underlying array can hold before a reallocation is needed. Keeping an eye on capacity matters in performance-sensitive code: pre-sizing a slice with make([]T, 0, expectedSize) avoids repeated reallocations when you know roughly how many elements you'll append.
Inspecting len and cap
package main
import "fmt"
func main() {
data := make([]int, 0, 4)
for i := 1; i <= 6; i++ {
data = append(data, i*i)
fmt.Printf("len=%d cap=%d data=%v\n", len(data), cap(data), data)
}
}- Declared with []Type — no length in the type, unlike arrays
- make([]Type, length, capacity) pre-allocates underlying storage
- append(slice, items...) grows a slice, reallocating when capacity is exceeded
- Slicing an array or slice with [low:high] shares the same underlying data
Exercise: Go Slices
What is a Go slice, in terms of its relationship to an underlying array?