GO: slices explained — Part 1

Alessandro Giovanardi
6 min readOct 23, 2019

--

In this GO (golang) tutorial I will showcase slices and their usage.

THEORY

  • Slices are composite data types which allows the manipulation of data stored in a underlying array.
  • A slice has three components: a pointer (to values of underlying array), a length and a capacity.
  • Unlike arrays, slices length, capacity and values can be modified.
  • Slices are access windows to underlying arrays.
  • Slices can be sliced ;)
  • Slice capacity can be set as len(m), where m is a map thus the slice’s length can adapt its capacity to the map’s growing size.
  • Slices are indexable.

CODE

Let’s start with empty nil slice . Zero value of a slice type is nil. A nil slice has no underlying array. Storing to nil slice will cause panic!

var sl []int    //nil slice
sl[0] = 43
fmt.Println(sl)
// output = panic: runtime error: index out of range [0] with length 0

We need to set values of the slice’s underlying array to make the slice usable:

var sl []int    //nil slicesl = []int{45, 54, 34, 53, 22, 521}    //assign values to slice
sl[0] = 999 //change value for index position 0 to 999
fmt.Println(sl) //output = [45 999 231 53 22 521]

A slice can also be created with built-in function make:

sl := make([]int, 5)    //creates a slice of type int, with length of 5 and equal capacity (omitted)sl2 := make([]float64, 6, 12) //creates a slice of type float64, with length of 6 and capacity of 12 explicitly

Alternatively we can create a slice using a predetermined set of values a.k.a. slice literal:

sl := [...]int{45,56,23,5,76,34,7,856,23,86}

Slice’s length and capacity can be retrieved with len(sl) and cap(sl).

Also, a slice can be created, given an array, with [low : high] expression:

arr := [5]int{1,2,3,4,5}
x := arr[0:5]

Low is the index of the array where to start the slice and high is the index of the array where to end the slice, with the last index value excluded.

We are allowed when coding to omit the low, high or even both as shown:

arr := [5]int{1,2,3,4,5}
arr[0:] // is the same as arr[0:len(arr)]
arr[:5] // is the same as arr[0:5]
arr[:] // is the same as arr[0:len(arr)]

As said a slice length and capacity is manipulable:

var sl []int    //empty nil slice
fmt.Println(sl) // output = []
sl = []int{45, 54, 34, 53, 22, 521} // sl length = 6, sl cap = 6sl = append(sl, 98, 345) // add new values to slice slfmt.Println(sl) // output = [45 54 34 53 22 521 98 345]
fmt.Println(len(sl), cap(sl)) // output = 8 (new length) 12 (new capacity)

When new values are appended to a slice, if the capacity of the slice is already fulfilled by array’s elements, the underlying array gets automatically copied into a double larger underlying array containing the original values and the newly added values.

Append to a slice

As seen above a way to add new elements to a slice’s underlying array is with built-in function append.
Append
adds elements onto the end of a slice. If current slice’s underlying array capacity is not sufficient the existing array gets copied into a newly generated underlying array with a double capacity compared to the original array and the new elements added at the end of it.

Doubling the size of the new array for each expansion avoid excessive numbers of allocations and ensure constant processing time on average.

Efficiency, readability, ease of programming. It’s GO fellas.

We can also append a slice to a slice:

sl := []int{45, 54, 34, 53, 22, 521}
sl2 := []int{111, 222, 333, 444, 555, 666}
sl3 := append(sl, sl2...) fmt.Println(sl3, len(sl3), cap(sl3)) // output = [45 54 34 53 22 521 111 222 333 444 555 666] 12 12

Watch out: you can’t append two slices of different types into a new unique slice, this will result in compilation error:

sl := []int{45, 54, 34, 53, 22, 521}
sl2 := []float64{111.1, 222.2, 333.3, 444.4, 555.5, 666.6}
sl3 := append(sl, sl2...) // this will result in errorfmt.Println(sl3, len(sl3), cap(sl3))// output = cannot use sl2 (type []float64) as type []int in append

Copy a slice into another slice

It’s possible to copy the content of a slice into another one with built-in function copy.

Copy takes two arguments: dst & src. Entries in src will be copied into dst.

Let’s see how:

sl := []int{1, 2, 3}
sl2 := []int{111, 222, 333, 444}
copy(sl2, sl) //copy content of sl to sl2
fmt.Println(sl2, len(sl2), cap(sl2))
// output = [1 2 3 444] 4 4

You can see that underlying array of slice sl has been copied into sl2. Since sl had only three entries, more specifically the first three elements of its underlying array, you can check how only the first three values of sl2 are changed while the last one remains as the original value.

What if we want to do the inverse? Let’s try to copy a longer slice onto a shorter one:

sl := []int{1, 2, 3}
sl2 := []int{111, 222, 333, 444}
copy(sl, sl2) //copy content of sl2 to sl
fmt.Println(sl, len(sl), cap(sl))
//output = [111 222 333] 3 3

As you can see since the length of sl is only 3 the first three elements of sl2 underlying array are copied into the slice sl, and sl length and capacity are not changed.

As for append you can’t use copy with two slices of different types. Doing this will result in a compilation error:

sl := []int{1, 2, 3}
sl2 := []float64{111.1, 222.2, 333.3, 444.4}
copy(sl, sl2) //copy content of sl2 to sl but different types! = err
fmt.Println(sl, len(sl), cap(sl))
// output = arguments to copy have different element types: []int
and []float64

Slicing a slice

As explained in how to create a slice we can use slicing to modify the output of a given slice and/or assign to a new slice. Slicing is also useful as an alternative to delete.

sl := []int{1, 2, 3, 4, 5}
sl2 := sl[1:3]
fmt.Println(sl2) // output = [2, 3]
sl = sl[3:4] // delete values from sl with slicing
fmt.Println(sl) // output = [4]

Delete from slice

Use append to delete from slice:

x := []int{4, 2, 56, 23, 36, 96}
x = append(x[:2], x[6:]…)
fmt.Println(“We DELETE from index 2 to index 6 excluded:”, x)

Multi dimensional slices

A slice can contain more than 1 underlying array:

//multi-dimensional slice 
twod := [][]int{x, z}
fmt.Println("Two dimensional slice:", twod)
//output = [[x1,x2..][z1,z2..]]

Iterate over a slice

To check the index & values of a slice we must use a loop. Iteration can use a for init/condition/post form or a range-based for loop:

x := []int{120, 100, 15, 0, 33, 5983, 1, 2, 3, 4, 5, 6,}//iterate over index and values with for init/cond/post
for i := 0; i <= len(x)-1; i++ {
fmt.Printf("At index %v we have number %d\n", i, x[i])
}
//iterate over slice with for range loop
for i, v := range x {
fmt.Printf("At index %v we have number %d\n", i, v)
}
/* At index 0 we have number 120
At index 1 we have number 100
At index 2 we have number 15
At index 3 we have number 0
At index 4 we have number 33
At index 5 we have number 5983
At index 6 we have number 1
At index 7 we have number 2
At index 8 we have number 3
At index 9 we have number 4
At index 10 we have number 5
At index 11 we have number 6
At index 0 we have number 120
At index 1 we have number 100
At index 2 we have number 15
At index 3 we have number 0
At index 4 we have number 33
At index 5 we have number 5983
At index 6 we have number 1
At index 7 we have number 2
At index 8 we have number 3
At index 9 we have number 4
At index 10 we have number 5
At index 11 we have number 6
*/

It’s a good practice to set condition of the first for loop as length of slice minus one, since if we set a definite number of iteration and the slice size grows we will miss some values. Also, it’s important to set len(x)-1 because if we try to iterate over the full lenght of the slice we will get an error like:

panic: runtime error: index out of range [12] with length 12

This happens since the length of the array is 12 but indexes start from 0.

That’s all folks!

Below you can find a code snippet showcasing all the Slices basic operations.

If you want to support my work feel free to send a tip:

$BTC: 1EtMQNXADe5ZoSgbwox7Ug5TPvP8YWSpL3

$QRL: Q010400e08175fe9823e6caa1aa3359686d7251a40eb432230d55f5b4e7388ec1c947b4361fb5cf

--

--

No responses yet