Slices
A slice is similar to an array, but it can grow when new elements are added.A slice always refers to an underlying array. What makes slices different fromarrays is that a slice is a pointer to an array; slices are referencetypes.
Reference types are created with make
. We detail this furtherin .
That means that if you assign one slice to another, both refer to the _same_underlying array. For instance, if a function takes a slice argument, changes itmakes to the elements of the slice will be visible to the caller, analogous topassing a pointer to the underlying array. With: slice := make([]int, 10)
, youcreate a slice which can hold ten elements. Note that the underlying array isn’tspecified. A slice is always coupled to an array that has a fixed size. Forslices we define a capacity and a length The image below shows the creation of an array,then the creation of a slice. First we create an array of (m) elements of thetype int
: var array[m]int
.
Next, we create a slice from this array: slice := array[:n]
. And now we have:
len(slice) == n
cap(slice) == m
len(array) == cap(array) == m
An array versus a slice.
Given an array, or another slice, a new slice is created via a[n:m]
. Thiscreates a new slice which refers to the variable a
, starts at index n
, andends before index m
. It has length n - m
.
a := [...]int{1, 2, 3, 4, 5} 1
s1 := a[2:4] 2
s2 := a[1:5] 3
s3 := a[:] 4
s4 := a[:4] 5
s5 := s2[:] 6
s6 := a[2:4:5] 7
First we define 1 an array with five elements, from index 0 to 4.From this we create 2 a slice with the elements from index 2 to 3, this slices contains: 3, 4
.Then we we create another slice 3 from a
: with the elements from index 1 to 4,this contains: 2, 3, 4, 5
.With a[:]
4 we create a slice with all the elements in the array. This is a shorthand for: a[0:len(a)]
.And with a[:4]
5 we create a slice with the elements from index0 to 3, this is short for: a[0:4]
, and gives us a slices that contains: 1, 2, 3, 4
.With s2[:]
we create a slice from the slice s2
6, note that s5
still refers to the array a
.Finally, we create a slice with the elements from index 3 to 3 and also set the cap to 4 7.
When working with slices you can overrun the bounds, consider this code.
package main
func main() {
var array [100]int 1
slice := array[0:99] 2
slice[98] = 1 3
slice[99] = 2 4
}
At 1 we create an array with a 100 elements, indexed from 0 to 99. Then at 2we create a slice that has index 0 to 98. We assign 1 to the 99th element 3 ofthe slice. This works as expected. But at 4 we dare to do the impossible, andand try to allocate something beyond the length of the slice and we are greetedwith a runtime error: Error: "throw: index out of range".
If you want to extend a slice, there are a couple of built-in functions thatmake life easier: append
and copy
. The append function appends zero or morevalues to a slice and returns the result: a slice with the same type as theoriginal. If the original slice isn’t big enough to fit the added values, appendwill allocate a new slice that is big enough. So the slice returned by appendmay refer to a different underlying array than the original slice does. Here’san example:
s0 := []int{0, 0}
s1 := append(s0, 2) 1
s2 := append(s1, 3, 5, 7) 2
s3 := append(s2, s0...) 3
At 1 we append a single element, making s1
equal to []int{0, 0, 2}
. At 2we append multiple elements, making s2
equal to []int{0, 0, 2, 3, 5, 7}
. Andat 3 we append a slice, giving us s3
equal to []int{0, 0, 2, 3, 5, 7, 0, 0}
.Note the three dots used after s0…
! This is needed make it clear explicit that you’re appending another slice, instead of a single value.
The copy function copies slice elements from a source to a destination, andreturns the number of elements it copied. This number is the minimum of thelength of the source and the length of the destination. For example:
var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
var s = make([]int, 6)
n1 := copy(s, a[0:]) 1
n2 := copy(s, s[2:]) 2
After 1, n1
is 6, and s
is []int{0, 1, 2, 3, 4, 5}
.And after 2, n2
is 4, and s
is []int{2, 3, 4, 5, 4, 5}
.