~/Go Rambling

Oct 12, 2024


In Go, slices are, as the name implies, slices of arrays. A slice is composed of a pointer to an underlying array, a length, and a capacity. The syntax to take a slice is arr[start:end], where start is inclusive, and end is exclusive.

Omitting start defaults to 0, and omitting end uses the slice/array’s length.

Model of a Slice

graph TD;


	subgraph Backing Array
    A[Backing Array];
    Length
    E[Capacity];
    end
    
    subgraph Slice
    B[Slice]
    
    D[Length];
    CAP[Capacity];
    end
    
    A --> Length
	B[Slice] -.- |reference|A[Backing Array]
    B --> D[Length];
    A --> E[Capacity];
    B --> CAP[Capacity];
    CAP -.-> |equal or less than|E;

slice expression examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// create a slice
//
[:]
// create a slice from index 0 to the end
//
[0:]
// create an empty slice
//
[:0]
// create a slice of 
// two elements at indexes 0 and 1
//
[:2]
// create a slice with 
// 10 elements and set the capacity to 100
//
[0:10:100]
// create an array        
x := [...]{1,2,3}   
// create a slice
y := x[:]            
1
2
3
4
 // set the element at index 2 to 1. [0 0 1]
[...]int{2: 1}
// [0 0 1 0 0 2]
[...]int{2: 1, 5: 2}

y := x[:] creates a shallow copy of the slice x in Go, both x and y share the same backing array.

1
2
3
4
x := []int{1, 2, 3}
y := x[:]  // shallow copy of x
x[0] = 10
fmt.Println(y[0]) // 10

playground


A backing array of a slice can potentially occupy a larger memory chunk than is needed leading to waste.

1
2
3
4
5
6
7
func f() []int {
	x := [...]int{9999: 1}
	return x[0:5]
}

y := f()
fmt.Println(cap(y))  // 1000

The simplest way to fix this is to create a new slice with its own backing array.

1
2
3
4
5
6
func f() []int {
	x := [...]int{9999: 1}
	z := make([]int, 0, 5)
	z = append(z, x[0:5]...)
	return z
}

playground

1
2
3
4
// Concatenate byte slices
slice1 := []byte("Hello, ")
slice2 := []byte("World!")
result := append(slice1, slice2...)

References

Tags: [Go]