Go Slices: Dynamic Arrays and Operations
Slices are one of Go’s most important data structures. They provide dynamic arrays with flexible sizing and powerful operations.
Slice Basics
Creating Slices
package main
import "fmt"
func main() {
// Slice literal
numbers := []int{1, 2, 3, 4, 5}
fmt.Println(numbers)
// Make with length
slice1 := make([]int, 5)
fmt.Println(slice1) // [0 0 0 0 0]
// Make with length and capacity
slice2 := make([]int, 3, 10)
fmt.Println(len(slice2), cap(slice2)) // 3 10
// Slice from array
arr := [5]int{1, 2, 3, 4, 5}
slice3 := arr[1:4]
fmt.Println(slice3) // [2 3 4]
}
Slice Length and Capacity
package main
import "fmt"
func main() {
slice := make([]int, 3, 10)
fmt.Println("Length:", len(slice)) // 3
fmt.Println("Capacity:", cap(slice)) // 10
// Append increases length
slice = append(slice, 1, 2, 3, 4)
fmt.Println("Length:", len(slice)) // 7
fmt.Println("Capacity:", cap(slice)) // 10
}
Slice Operations
Appending Elements
package main
import "fmt"
func main() {
slice := []int{1, 2, 3}
// Append single element
slice = append(slice, 4)
fmt.Println(slice) // [1 2 3 4]
// Append multiple elements
slice = append(slice, 5, 6, 7)
fmt.Println(slice) // [1 2 3 4 5 6 7]
// Append another slice
other := []int{8, 9}
slice = append(slice, other...)
fmt.Println(slice) // [1 2 3 4 5 6 7 8 9]
}
Slicing Operations
package main
import "fmt"
func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// Slice from index to index
fmt.Println(numbers[2:5]) // [3 4 5]
// Slice from beginning
fmt.Println(numbers[:3]) // [1 2 3]
// Slice to end
fmt.Println(numbers[7:]) // [8 9 10]
// Full slice
fmt.Println(numbers[:]) // [1 2 3 4 5 6 7 8 9 10]
}
Copying Slices
package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
// Shallow copy (reference)
reference := original
reference[0] = 999
fmt.Println(original) // [999 2 3 4 5]
// Deep copy
original2 := []int{1, 2, 3, 4, 5}
copy := make([]int, len(original2))
copy(copy, original2)
copy[0] = 999
fmt.Println(original2) // [1 2 3 4 5]
}
Removing Elements
package main
import "fmt"
func main() {
slice := []int{1, 2, 3, 4, 5}
// Remove element at index 2
index := 2
slice = append(slice[:index], slice[index+1:]...)
fmt.Println(slice) // [1 2 4 5]
// Remove first element
slice = slice[1:]
fmt.Println(slice) // [2 4 5]
// Remove last element
slice = slice[:len(slice)-1]
fmt.Println(slice) // [2 4]
}
Slice Iteration
Range Iteration
package main
import "fmt"
func main() {
numbers := []int{10, 20, 30, 40, 50}
// Iterate with index and value
for i, v := range numbers {
fmt.Printf("Index: %d, Value: %d\n", i, v)
}
// Iterate with index only
for i := range numbers {
fmt.Printf("Index: %d\n", i)
}
// Iterate with value only
for _, v := range numbers {
fmt.Printf("Value: %d\n", v)
}
}
Slice Patterns
Filtering Slice
package main
import "fmt"
func filterEven(numbers []int) []int {
var result []int
for _, n := range numbers {
if n%2 == 0 {
result = append(result, n)
}
}
return result
}
func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
evens := filterEven(numbers)
fmt.Println(evens) // [2 4 6 8 10]
}
Mapping Slice
package main
import "fmt"
func double(numbers []int) []int {
result := make([]int, len(numbers))
for i, n := range numbers {
result[i] = n * 2
}
return result
}
func main() {
numbers := []int{1, 2, 3, 4, 5}
doubled := double(numbers)
fmt.Println(doubled) // [2 4 6 8 10]
}
Reducing Slice
package main
import "fmt"
func sum(numbers []int) int {
total := 0
for _, n := range numbers {
total += n
}
return total
}
func main() {
numbers := []int{1, 2, 3, 4, 5}
total := sum(numbers)
fmt.Println(total) // 15
}
Best Practices
โ Good: Pre-allocate Slices
// DO: Pre-allocate when size is known
slice := make([]int, 0, 1000)
for i := 0; i < 1000; i++ {
slice = append(slice, i)
}
โ Bad: Repeated Allocation
// DON'T: Repeatedly allocate without capacity
var slice []int
for i := 0; i < 1000; i++ {
slice = append(slice, i) // Reallocates frequently
}
โ Good: Use Copy for Deep Copy
// DO: Use copy() for deep copying
original := []int{1, 2, 3}
copied := make([]int, len(original))
copy(copied, original)
โ Good: Check Bounds
// DO: Check slice bounds
if index >= 0 && index < len(slice) {
value := slice[index]
}
Summary
Go slices provide:
- Dynamic sizing with append
- Efficient slicing operations
- Range iteration for easy access
- Copy semantics for data safety
- Powerful patterns for data manipulation
These features make slices essential for Go programming.
Comments