Core Characteristics
In Go, slices are reference types composed of three components: a pointer to the underlying array, length, and capacity. This combination forms the slice header.
Key features include:
- Dynamic size - length and capacity can differ
- Reference semantics - copies share the same underlying data
- Built on arrays for efficient indexed access
Declaration Methods
Literal Initialization
var numbers = []int{10, 20, 30}
fmt.Printf("%T %v", numbers, numbers) // Output: []int [10 20 30]
Empty Slice (Not Recommended)
var empty []string
fmt.Println(len(empty), cap(empty)) // Output: 0 0
Using make (Recommended)
data := make([]float64, 3, 5)
fmt.Println(data, len(data), cap(data)) // Output: [0 0 0] 3 5
Memory Model
The slice header contains:
- Pointer to array elements
- Current length (accessible elements)
- Total capacity (maximum elements before relalocation)
values := []int{1, 2, 3}
fmt.Printf("%p %p", &values, &values[0]) // Different addresses
Appending Elements
The append function returns a new header, potentially triggering reallocation:
nums := make([]int, 2, 4)
nums = append(nums, 5)
fmt.Println(nums, len(nums), cap(nums)) // Output: [0 0 5] 3 4
Sub-slice Operations
Basic Syntax
Create views of existing slices with [start:end] notation:
mainSlice := []int{10, 20, 30, 40, 50}
subSlice := mainSlice[1:4] // [20 30 40]
fmt.Println(len(subSlice), cap(subSlice)) // Output: 3 4
Memory Sharing
Sub-slices share the same underlying array:
original := []int{1, 2, 3, 4}
view := original[1:3]
view[0] = 99
fmt.Println(original) // Output: [1 99 3 4]
Capacity Calculation
Sub-slice capacity extends from start index to end of array:
full := []int{0, 1, 2, 3, 4}
partial := full[2:4] // capacity = 3 (indices 2-4)
fmt.Println(len(partial), cap(partial)) // Output: 2 3
Practical Considerations
Growth Strategy
Go's slice growth algorithm:
- Below 256 elements: double capacity
- Above 256: 1.25x growth plus fixed buffer
Performence Tips
- Pre-allocate with make when size is known
- Avoid frequent small appends
- Remember sub-slice modifications affect parent
Common Operations
Removing Duplicates
func deduplicate(s []int) []int {
seen := make(map[int]bool)
result := []int{}
for _, v := range s {
if !seen[v] {
seen[v] = true
result = append(result, v)
}
}
return result
}
Reversing Elements
func reverse(s []int) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}