Fundamentals 10 min read

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.

360 Zhihui Cloud Developer
360 Zhihui Cloud Developer
360 Zhihui Cloud Developer
Unlock Go’s Slice Secrets: Structure, Memory, and Best Practices

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.

backendgolangGodata structuresMemoryslice
360 Zhihui Cloud Developer
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.