Unlock Go’s Slice Secrets: Structure, Memory, and Best Practices
This article explains Go's slice data structure, how slices are represented in memory, common pitfalls with value passing, slicing, expanding, and provides practical examples of functions like copy, append, and differences between make and new for slices.
1. Slice Data Structure
In Go, a slice is defined in $YOUR_GO_DIR/src/runtime/slice.go as:
<code>type slice struct {
// pointer to the underlying array (similar to C's void*)
array unsafe.Pointer
len int // length
cap int // capacity
}</code>A slice created with make([]int, 10, 20) consists of two parts: the slice header (the struct above) and the underlying array that stores the elements.
In later sections the article refers to this struct as SliceHeader , a term borrowed from Rob Pike’s Golang/slices blog.
2. Slice Usage Tips
2.1 Value Passing
Go passes arguments by value. When a slice is passed to a function, the function receives a copy of the SliceHeader that still points to the same underlying array, so modifications affect the original data.
<code>s := make([]string, 10)
saveSlice(s)</code>Inside saveSlice the parameter s is a new variable whose header points to the same array, sharing the same len and cap .
Experiment shows that changing an element inside the function updates the original slice, confirming that only the header is copied.
<code>// before
fmt.Println("before:", data)
changeIndex0(data)
// after
fmt.Println("after:", data)</code> <code>func changeIndex0(data []int) {
data[0] = 99
}</code>Result:
<code>before: [0 0 0 0 0 0 0 0 0 0]
after: [99 0 0 0 0 0 0 0 0 0]</code>The SliceHeader occupies 24 bytes (8 bytes pointer + 8 bytes len + 8 bytes cap on a 64‑bit system), while a pointer is only 8 bytes, so the memory overhead of passing a slice versus a pointer is minimal.
2.2 Slicing and Expanding
Slices are built from a fixed‑size array; changing the array length requires allocating a new array.
When you create a sub‑slice, it shares the original array:
<code>data := make([]int, 10)
subSlice(data)</code> <code>func subSlice(data []int) {
data[0] = 99
data = data[0:8]
fmt.Println("inside:", data, len(data), cap(data))
}</code> <code>before: [0 0 0 0 0 0 0 0 0 0] 10 10
inside: [99 0 0 0 0 0 0 0] 8 10
after: [99 0 0 0 0 0 0 0 0 0] 10 10</code>To obtain an independent sub‑slice you can copy the desired range:
<code>sub := make([]int, 2)
copy(sub, data[3:5])</code>Expanding a slice is typically done with append , which allocates a larger array (often double the capacity) and copies the existing elements:
<code>fmt.Printf("before: len=%d cap=%d\n", len(data), cap(data))
data = append(data, 5)
fmt.Printf("after: len=%d cap=%d\n", len(data), cap(data))</code> <code>before: len=10 cap=10
after: len=11 cap=20</code>3. Common Slice Functions
copy() – copies elements from one slice to another, stopping at the shorter length.
append() – adds elements, allocating a new underlying array when necessary.
4. Other Details
4.1 Strings
In the runtime source, a string is defined as:
<code>type stringStruct struct {
str unsafe.Pointer
len int
}</code>Thus a Go string is essentially a read‑only byte slice.
4.2 Nil Slices
Creating a slice with new([]int) yields a nil slice, whereas make([]int, 0) produces a non‑nil empty slice.
<code>nilSlice := new([]int)
fmt.Printf("nilSlice is nil: %v\n", *nilSlice == nil)
emptySlice := make([]int, 0)
fmt.Printf("emptySlice is nil: %v\n", emptySlice == nil)</code> <code>nilSlice is nil: true
emptySlice is nil: false</code>new() allocates memory and zero‑initialises it; make() also allocates but initialises the slice header to point to an array (even if length is zero).
5. Conclusion
Understanding the internal representation, memory behavior, and common operations of Go slices helps developers use them efficiently and avoid subtle bugs in real‑world projects.
360 Zhihui Cloud Developer
360 Zhihui Cloud is an enterprise open service platform that aims to "aggregate data value and empower an intelligent future," leveraging 360's extensive product and technology resources to deliver platform services to customers.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.