Golang Slices

Intro

A slice in Golang is an abstraction that sits on top of an array. An array normally has a set size and must be initialised with a size. A slice is a little more like an array in javascript or an ArrayList in Java.

A slice is a descriptor of an array segment. It consists of a pointer to the array, the length of the segment, and its capacity (the maximum length of the segment). The internals of a slice are quite clever and mean that working with a slice is as efficient as working with an array. Read more: slice internals.

It is unusual in Golang to use an array and for our needs it is unlikely you will need one, so we will focus on slices. As with maps a slice is not naturally thread safe. As with maps we will go over these things when we get to concurrency.

Define slice

As with a map there are two ways of making a slice.

1) Slice literals

package main

import "fmt"

func main (){
    captains := []string{"Picard","Janeway","Kirk"} //the type the slice will hold must be specified
    fmt.Println(captains)
}

playground

2) As with maps you can use the make function

package main

import "fmt"

func main (){
    captains := make([]string,3) //notice the second arg here, this is the initial length and is required in the case of a slice
    captains[0] = "Picard"
    captains[1] = "Janeway"
    captains[2] = "Kirk"
    fmt.Println(captains)
}

playground

Slicing a slice

Slices can be re-sliced, creating a new slice value that points to the same array.

The expression s[lo:hi] evaluates to a slice of the elements from lo through hi-1, inclusive. Thus s[lo:lo] is empty and s[lo:lo+1] has one element.

Note: lo and hi would be integers representing indexes.

package main

import "fmt"

func main() {
    mySlice := []int{2, 3, 5, 7, 11, 13}
    fmt.Println(mySlice) // [2 3 5 7 11 13]

    fmt.Println(mySlice[1:4]) // [3 5 7]

    // missing low index implies 0
    fmt.Println(mySlice[:3]) // [2 3 5]

    // missing high index implies len(s)
    fmt.Println(mySlice[4:]) // [11 13]
}

Appending to a slice

To add new items to a slice we use the built in append function. append takes the original slice as it’s first argument and any number of follwing args to append to that slice. It returns the new slice to you.

package main

import "fmt"

func main (){
    captains := make([]string,0) //notice the second arg here, this is the initial length
    captains =  append(captains,"Picard","Janeway","Kirk") //append takes any number of additions
    fmt.Println(captains)
}

Appending slice to other slice

And you can also append a slice to another using an ellipsis:

package main

import "fmt"

func main() {
    cities := []string{"San Diego", "Mountain View"}
    otherCities := []string{"Santa Monica", "Venice"}
    cities = append(cities, otherCities...)
    fmt.Printf("%q", cities)
    // ["San Diego" "Mountain View" "Santa Monica" "Venice"]
}

Note that the ellipsis is a built-in feature of the language that means that the element is a collection. We can’t append an element of type slice of strings ([]string) to a slice of strings, only strings can be appended. However, using the ellipsis (...) after our slice, we indicate that we want to append each element of our slice. Because we are appending strings from another slice, the compiler will accept the operation since the types are matching.

You obviously can’t append a slice of type []int to another slice of type []string.

Getting the length of a slice

This is the same as a map, you make use of the builtin len function.

package main


import "fmt"


func main (){
    captains := []string{"Picard","Janeway","Kirk"} //the type the slice will hold must be specified
    length := len(captains)
    fmt.Println(length)
}

playground

Iterate through a slice

Once again we will use the range key word. After all underneath every good map is an array.

package main

import "fmt"

func main (){
    captains := []string{"Picard","Janeway","Kirk"}
    for index,value := range captains{
        fmt.Printf("index %d value %s",index,value)
    }
}

playground

Delete an item from a slice

To delete an item from a slice we need to get a new slice with the element removed. To do this we use the append function to append all the items but the one we don’t want.

package main

import "fmt"

func main (){
    captains := []string{"Picard","Black Beard", "Janeway","Kirk"}
    captains = append(captains[:1],captains[2:]...) //lets take a minute and go over this
    fmt.Println(captains)
}

So what is happening here. It looks a little strange.

We are assigning the returned slice from append to the captains reciever. Inside append we are appending everything after the [2] index to everything before the [1] first index. So cutting out the value at [1] [:1] before [2:] after.

The ... is how Golang declares a variadic argument. So can be read as every value including the one at the [2] index.

playground

Nil slices

The zero value of a slice is nil. A nil slice has a length and capacity of 0.

package main

import "fmt"

func main() {
    var z []int
    fmt.Println(z, len(z), cap(z))
    // [] 0 0
    if z == nil {
        fmt.Println("nil!")
    }
    // nil!
}

Reference

http://www.golangbootcamp.com/book/collection_types


See also