Slices in Go
A slice is a data structure similar to an array, but it can change in size.
Under the hood, slices use an array and they are an abstraction built on top of them that makes them more flexible and useful (think about arrays as lower level).
You will use slices in a way that’s very similar to how you use arrays in higher level languages.
You define a slice similarly to an array, omitting the length:
var mySlice []string //a slice of strings
You can initialize the slice with values:
var mySlice = []string{"First", "Second", "Third"}
//or
mySlice := []string{"First", "Second", "Third"}
You can create an empty slice of a specific length using the make()
function:
mySlice := make([]string, 3) //a slice of 3 empty strings
You can create a new slice from an existing slice, appending one or more items to it:
mySlice := []string{"First", "Second", "Third"}
newSlice := append(mySlice, "Fourth", "Fifth")
Note that we need to assign the result of append()
to a new slice, otherwise we’ll get a compiler error. The original slice is not modified, we’ll get a brand new one.
You can also use the copy()
function to duplicate a slice so it does not share the same memory of the other one and is independent:
mySlice := []string{"First", "Second", "Third"}
newSlice := make([]string, 3)
copy(newSlice, mySlice)
If the slice you’re copying to does not have enough space (is shorter than the original) only the first items (until there’s space) will be copied.
You can initialize a slice from an array:
myArray := [3]string{"First", "Second", "Third"}
mySlice = myArray[:]
Multiple slices can use the same array as the underlying array:
myArray := [3]string{"First", "Second", "Third"}
mySlice := myArray[:]
mySlice2 := myArray[:]
mySlice[0] = "test"
fmt.Println(mySlice2[0]) //"test"
Those 2 slices now share the same memory and modifying one slice modifies the underlying array and causes the other slice generated from the array to be modified too.
As with arrays, each item in a slice is stored in memory in consecutive memory locations.
If you know you need to perform operations to the slice, you can request it to have more capacity than initially needed, so when you need more space, the space will be readily available (instead of finding and moving the slice to a new memory location with more space to grow and dispose via garbage collection of the old location).
We can specify the capacity adding a third parameter to make()
:
newSlice := make([]string, 0, 10)
//an empty slice with capacity 10
As with strings, you can get a portion of a slice using this syntax:
mySlice := []string{"First", "Second", "Third"}
newSlice := mySlice[:2] //get the first 2 items
newSlice2 := mySlice[2:] //ignore the first 2 items
newSlice3 := mySlice[1:3] //new slice with items in position 1-2
→ I wrote 17 books to help you become a better developer, download them all at $0 cost by joining my newsletter
→ JOIN MY CODING BOOTCAMP, an amazing cohort course that will be a huge step up in your coding career - covering React, Next.js - next edition February 2025