Go by Example: Slices
Slices are the most common way to work with sequences of data in Go. Unlike arrays, they are dynamic. This example explains length vs. capacity, the `append` function, and how slices are actually "windows" into underlying arrays.
Code
package main
import "fmt"
func main() {
// 1. Creating Slices
// Using make(type, length, capacity)
// Length: number of elements accessible
// Capacity: space in underlying array
s := make([]string, 3)
fmt.Println("Empty slice:", s)
fmt.Printf("Len: %d, Cap: %d\n", len(s), cap(s))
// 2. Setting Values
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("Set:", s)
// 3. Appending
// append() returns a new slice (may point to new memory)
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println("Appended:", s)
fmt.Printf("Len: %d, Cap: %d\n", len(s), cap(s))
// 4. Slicing (The "Window" Concept)
// slice[low:high] (high is exclusive)
l := s[2:5]
fmt.Println("Slice s[2:5]:", l)
// 5. Copying
// copy(dst, src) copies min(len(dst), len(src)) elements
c := make([]string, len(s))
copy(c, s)
fmt.Println("Copy:", c)
// 6. Slice Literal
t := []string{"g", "h", "i"}
fmt.Println("Literal:", t)
}
Explanation
In the Go programming language, slices represent a sophisticated, dynamic abstraction over standard arrays, providing a flexible and efficient mechanism for managing sequences of typed data. Unlike fixed-size arrays, slices are composite data structures that act as a "window" or descriptor for an underlying backing array, encapsulating a pointer to the memory block, the current length of the segment, and the total capacity available for expansion. This architecture allows for efficient memory manipulation and lightweight passing of data references without the performance overhead associated with copying entire data structures.
The built-in append function exemplifies the dynamic nature of slices by automatically managing memory allocation; when a slice exceeds its current capacity, the runtime seamlessly allocates a larger contiguous memory block and copies existing elements, thereby abstracting complex memory management tasks from the developer. This behavior ensures that slices remain performant while offering the convenience of dynamic resizing, although developers must remain cognizant of the underlying memory mechanics to avoid inadvertent side effects when multiple slices reference the same backing array.
- Dynamic: Can grow using
append. - Reference: Slicing
s[i:j]creates a new view of the same array. - Length vs Capacity:
len()is current size,cap()is max size before reallocation. - Zero Value: The zero value of a slice is
nil.

