Go Slices
A slice is a flexible, dynamic view into an array. Unlike arrays, slices can grow and shrink. Slices are the most commonly used data structure in Go for working with lists of elements.
Creating a Slice
Slice Literal
package main
import "fmt"
func main() {
fruits := []string{"Apple", "Banana", "Mango"}
fmt.Println(fruits) // [Apple Banana Mango]
fmt.Println(len(fruits)) // 3
}
Using make
package main
import "fmt"
func main() {
scores := make([]int, 5) // creates a slice of 5 zeros
fmt.Println(scores) // [0 0 0 0 0]
}
Slice Internal Structure
A slice has three parts:
┌───────────────────────────────────┐
│ pointer │ length │ capacity │
│ to array │ (len) │ (cap) │
└───────────────────────────────────┘
pointer → points to the underlying array
length → number of elements currently in the slice
capacity → total space available before reallocation
Appending to a Slice
Use append to add elements. If the slice runs out of capacity, Go automatically allocates a larger underlying array.
package main
import "fmt"
func main() {
nums := []int{1, 2, 3}
nums = append(nums, 4)
nums = append(nums, 5, 6, 7)
fmt.Println(nums) // [1 2 3 4 5 6 7]
}
Slicing a Slice
A sub-slice is created using the [low:high] syntax. The result includes elements from index low up to but not including index high.
package main
import "fmt"
func main() {
letters := []string{"A", "B", "C", "D", "E"}
fmt.Println(letters[1:4]) // [B C D]
fmt.Println(letters[:3]) // [A B C]
fmt.Println(letters[2:]) // [C D E]
}
Slicing Diagram
letters := ["A", "B", "C", "D", "E"]
Index: 0 1 2 3 4
letters[1:4] → elements at index 1, 2, 3 → [B C D]
(includes 1, excludes 4)
Slices Share the Underlying Array
A sub-slice points to the same memory as the original. Modifying the sub-slice changes the original slice too.
package main
import "fmt"
func main() {
original := []int{10, 20, 30, 40, 50}
sub := original[1:4]
sub[0] = 999
fmt.Println(original) // [10 999 30 40 50] ← changed!
fmt.Println(sub) // [999 30 40]
}
To avoid this shared-memory issue, use copy to create an independent slice.
Copying a Slice
package main
import "fmt"
func main() {
src := []int{1, 2, 3, 4, 5}
dst := make([]int, len(src))
copy(dst, src)
dst[0] = 100
fmt.Println(src) // [1 2 3 4 5] — unchanged
fmt.Println(dst) // [100 2 3 4 5]
}
Deleting an Element from a Slice
Go has no built-in delete for slices. The standard pattern appends the elements before and after the target index.
package main
import "fmt"
func main() {
items := []string{"A", "B", "C", "D"}
i := 2 // delete index 2 ("C")
items = append(items[:i], items[i+1:]...)
fmt.Println(items) // [A B D]
}
2D Slice
package main
import "fmt"
func main() {
matrix := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
for _, row := range matrix {
fmt.Println(row)
}
}
Output:
[1 2 3]
[4 5 6]
[7 8 9]
Key Slice Functions
| Operation | Code |
|---|---|
| Length | len(s) |
| Capacity | cap(s) |
| Append element | s = append(s, val) |
| Append slice | s = append(s, other...) |
| Copy | copy(dst, src) |
| Sub-slice | s[low:high] |
Key Points
- Slices are dynamic — they grow automatically with
append - A slice has a pointer, length, and capacity
- Sub-slices share memory with the original — use
copyfor independence - The
[low:high]syntax includeslowand excludeshigh - Slices are preferred over arrays in most Go programs
