Slices in Go: Essential Guide
Basics of Slices
// Declaration & Initialization
var empty []int // nil slice
letters := []string{"a", "b"} // slice literal
nums := make([]int, 3, 5) // length=3, capacity=5Key Characteristics⭐
- Dynamic size (unlike arrays)
- Reference type (backed by an array)
- Three components:
- Pointer to underlying array
- Length (number of elements)
- Capacity (max size before reallocation)
Core Operations
Creating Slices
| Operation | Example | Description |
|---|---|---|
| From array | arr[1:4] | Creates slice from array |
| From slice | slice[:3] | New slice from existing |
| Make | make([]T, len, cap) | Pre-allocated slice |
Common Methods
s := []int{1, 2}
s = append(s, 3) // [1, 2, 3]
copy(dest, src) // Copies elements
len(s), cap(s) // Get dimensionsCritical Points to Remember
-
Underlying Array Sharing⭐
a := []int{1, 2, 3} b := a[:2] // Shares same array b[0] = 9 // Modifies a[0] too! -
Append Behavior
- May allocate new array if capacity exceeded
- Original slice unaffected if new allocation occurs
-
Nil vs Empty
var nilSlice []int // nil (len=0, cap=0) empty := []int{} // non-nil (len=0, cap=0) -
Capacity Rules.⭐
- Append doubles capacity until 1024 elements
- Then grows by 25% each time
Performance Considerations
Do:
- Pre-allocate with
make()when size is known - Reuse slices with
slice = slice[:0](clear without reallocation)
Don’t:
- Append in loops without pre-allocation
- Assume append won’t modify original slice
- Forget that subslices share memory
Common Pitfalls
-
Memory Leaks
func leak() []int { big := make([]int, 1e6) return big[:10] // Holds reference to 1M elements! } -
Accidental Modifications
original := []int{1, 2, 3} subset := original[1:3] subset[0] = 9 // Modifies original[1] -
Append Gotchas
s := []int{1, 2, 3} s = append(s, 4) // May or may not modify original
📚 FAQ
❓ What is a slice in Go?
A slice is a dynamically-sized, flexible view into the elements of an array. Unlike arrays, slices can grow and shrink.
❓ How is a slice different from an array in Go?
- Arrays have a fixed size; slices are dynamically sized.
- Arrays are value types; slices are reference types.
- Slices internally contain a pointer to the array, length, and capacity.
❓ What is the zero value of a slice?
The zero value of a slice is nil, which has a length and capacity of 0.
❓ How do you create a slice in Go?
s := []int{1, 2, 3} // Using a literal
s := make([]int, 5) // Using make
s := arr[1:4] // Slicing an array or slice❓ What are length and capacity of a slice?
len(slice)→ number of elements.cap(slice)→ number of elements in the underlying array from the start index to the end.
❓ Can slices be resized in Go?
Yes. You can append to a slice using append(), which may create a new underlying array.
❓ What happens when a slice exceeds its capacity?
Go allocates a new array (usually double the size), copies the existing elements to it, and returns a new slice.
❓ Are slices passed by reference or value?
Slices are passed by value, but since they contain a reference to the underlying array, changes to elements inside the function affect the original data.
❓ How do you copy a slice?
Use the built-in copy() function:
dst := make([]int, len(src))
copy(dst, src)❓ How do you delete an element from a slice?
Use slicing and append():
s = append(s[:i], s[i+1:]...) // remove element at index i❓ Can you compare two slices using ==?
No. Only nil slices can be compared using ==. For deep equality, use reflect.DeepEqual() or manually compare elements.
❓ What is the difference between nil slice and empty slice?
var s []int→nilslice (len=0,cap=0,s==nil)s := []int{}→ empty slice (len=0,cap=0,s!=nil)
❓ What is the underlying structure of a slice? 🔥🔥
A slice internally contains:
type slice struct {
ptr *T // pointer to array
len int // current number of elements
cap int // max elements before resizing
}❓ What happens when you append to a nil slice?
Appending to a nil slice works the same as appending to an empty slice. Go allocates the memory as needed.
❓ Can you slice a slice?
Yes. You can slice a slice multiple times:
s1 := []int{1, 2, 3, 4}
s2 := s1[1:3] // s2 = [2, 3]⚡ Array vs Slice in Go
| Feature | Array | Slice |
|---|---|---|
| Size | Fixed | Dynamic (can grow/shrink) |
| Type | Value type | Reference type |
| Memory | All data copied on assignment | Only slice descriptor copied (shallow copy) |
| Creation | var a [5]int | var s []int or slicing an array |
| Common Use | Rare (low-level memory control) | Very common |
| Performance | No hidden cost | Some overhead due to dynamic growth and possible copying |