Understanding Slices in Go
Slices are built on top of arrays and provide dynamic resiizng capabilities. They can be passed around efficiently without copying the underlying data. Internally, a slice is represented by three components:
- A pointer to the underlying array
- The current length of the slice
- The total capacity allocated for the slice
Creating Slices
Slices can be created in two primary ways: from an existing array or directly.
Creating from an Array
A slice can reference a portion or the entirety of an existing array.
package main
import "fmt"
func main() {
numbers := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
partialSlice := numbers[3:8]
fmt.Println("Full array:", numbers)
fmt.Println("Slice from index 3 to 7:", partialSlice)
}
Direct Creation
The make funcsion allows for direct slice creation with control over initial length and capacity.
func main() {
sliceA := make([]string, 3) // Length 3, capacity 3
sliceB := make([]float64, 5, 10) // Length 5, capacity 10
sliceC := []bool{true, false, true} // Length 3, capacity 3
}
Iterating Over Elements
Slices support all standard iteration methods available for arrays.
func main() {
data := []string{"apple", "banana", "cherry"}
// Using index
for i := 0; i < len(data); i++ {
fmt.Println(data[i])
}
// Using range
for index, value := range data {
fmt.Printf("Index %d: %s\n", index, value)
}
}
Dynamic Resizing
A key advantage of slices over arrays is their ability to grow and shrink. The len() function returns the current number of elements, while cap() returns the allocated capacity.
func main() {
mySlice := make([]int, 2, 4)
fmt.Printf("Length: %d, Capacity: %d\n", len(mySlice), cap(mySlice))
}
The append function adds elements to a slice, handling reallocation automatically if capacity is exceeded.
func main() {
items := make([]int, 0, 3)
items = append(items, 10) // Add single element
items = append(items, 20, 30, 40) // Add multiple elements
moreItems := []int{50, 60}
items = append(items, moreItems...) // Append another slice
}
When a slice's capacity is insufficient, Go automatically allocates a larger underlying array. The growth strategy typically doubles the capacity for slices under 1024 elements, then increases by 25% thereafter.
Creating Slices from Other Slices
New slices can be created from existing slices, sharing the same underlying array.
func main() {
original := []int{100, 200, 300, 400, 500}
newView := original[1:4] // Contains [200, 300, 400]
fmt.Println(newView)
}
Note: The end index in a slice expression can exceed the current length but must not exceed the capacity. Elements beyond the current length will have the zero value.
Copying Data
Use the copy function to duplicate elements between slices. It copies the minimum number of elements based on the smaller slice's length.
func main() {
source := []int{1, 2, 3, 4, 5}
destination := make([]int, 3)
count := copy(destination, source)
fmt.Printf("Copied %d elements: %v\n", count, destination)
}