Slice Operations

Let’s review some common slice operations.

Add Elements

In Go, we can use append method to add elements, which is similar to Python’s syntax.

1
2
3
4
5
6
7
8
9
10
11
func main(){
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]
s2 := s1[3:5]
s3 := append(s2, 10)
s4 := append(s3, 11)
s5 := append(s4, 12)

fmt.Println("s3, s4, s5 =",s3, s4, s5)
fmt.Println("arr =", arr)
}

The output will be:

1
2
s3, s4, s5 = [5 6 10] [5 6 10 11] [5 6 10 11 12]
arr = [0 1 2 3 4 5 6 10]

There are a couple of things happening under the hood here:

  • When s3 := append(s2, 10) is invoked, 7 in the original array is replaced by 10.
  • When s4 := append(s3, 11) and s5 := append(s4, 12) are invoked, s4 and s5 are no longer views of arr. A new array is created to store 11 and 12, and s4 s5 became the views of the newly created array.
  • If the added elements extends the array capacity, a new array with greater capacity will be automatically created by the system.
  • Go also has garbage collection system, if arr is not used anywhere, it will be recycled by the system

Create Slices

Create an Empty Slice

In previous examples, we created slices based on arrays. This is actually not necessary. Creating slices directly is actually even simpler than creating arrays.

1
var s []int

Go will assign a Zero value nil for the slice without initial assignments when created.

Create a Slice without assigning size

This is what we’ve done before, creating a slice based on an array.

1
s1 := []{2,4,6,8}

Create a Slice without assigning initial values

Often, we know the size of the slice but not its initial elements. We can use make method

  • To make a slice with length of 16

    1
    s2 := make([]int, 16)
  • To make a slice with length of 16 and capacity of 32

    1
    s3 := make([]int, 16, 32)

Build a function to print out slice info

1
2
3
4
5
6
7
8
9
10
func printSliceInfo(s []int){
fmt.Printf("%v, len(s) = %d, cap(s) = %d\n", s, len(s), cap(s))
}

func main(){
s2 := make([]int, 16)
s3 := make([]int, 16, 64)
printSliceInfo(s2)
printSliceInfo(s3)
}

The outputs will be:

1
2
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], len(s) = 16, cap(s) = 16
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], len(s) = 16, cap(s) = 64

Copy Slices

Go has a built-in method copy. It takes two arguments, copy(dest, src)

1
2
3
fmt.Println(s1, s2)
copy(s2, s1)
fmt.Println(s1, s2)

The outputs are:

1
2
3
4
[2 4 6 8], len(s) = 4, cap(s) = 4
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], len(s) = 16, cap(s) = 16
[2 4 6 8], len(s) = 4, cap(s) = 4
[2 4 6 8 0 0 0 0 0 0 0 0 0 0 0 0], len(s) = 16, cap(s) = 16

Deleting Slice Elements

Go doesn’t have built-in delete method (well In Python we have remove and pop). But it’s not hard with slices.

E.g. if we want to remove element 8 in s2, we could do the following

  • Get a slice with first 3 elements s2[:3]
  • Get another slice with elements after 8 s2[4:]
  • Append the 2nd slice elements (use ..., similar to object destructuring in javascript) to the first slice
1
2
s4 := append(s2[:3], s2[4:]...)
printSliceInfo(s4)

The outputs will be:

1
[2 4 6 0 0 0 0 0 0 0 0 0 0 0 0], len(s) = 15, cap(s) = 16

Popping

Popping element is more common. However, there’s no built-in “pop” methods in Go.

  • To perform popping from front
1
2
front := s2[0]
s2 = s2[1:]

The outputs will be:

1
2
2 
[4 6 0 0 0 0 0 0 0 0 0 0 0 0 0]
  • To perform popping from tail
1
2
tail := s2[len(s2)-1]
s2 := s2[:len(s2)-1]

The output will be:

1
2
0 
[4 6 0 0 0 0 0 0 0 0 0 0 0 0]