What a slice is
An array in Go has a fixed size. Once you write [3]string, the array holds exactly three strings for its whole life, and the length is part of the type. A slice removes that limit. It is an ordered list of values of one type that can grow and shrink while the program runs.
You will use slices far more than arrays. Almost every Go function that works with a list of things takes or returns a slice.
Declaring a slice
The type of a slice is written [] followed by the element type. Compare the two forms:
var a [3]string // an array: the length 3 is part of the type
var s []string // a slice: no length in the brackets
A slice declared with var and no value is empty. It holds no elements, its length is 0, and it equals nil. That is a perfectly usable state, and you can add elements to it later:
var sandwich []string
fmt.Println(sandwich == nil, len(sandwich), sandwich)
true 0 []
Creating a slice with values
Most of the time you create a slice together with its first values, using a slice literal: the type, then the values between curly braces and separated by commas.
sandwich := []string{"peanut butter", "jelly", "bread"}
animals := []string{"cat", "cat", "cat", "cat", "cat"}
The compiler works out the type of the variable from the literal, so sandwich is a []string with three items and animals is a []string with five. Duplicate values are fine: a slice is a list, not a set.
Declaring with := or var
The short form := declares a variable and gives it a value in one step. It only works inside a function. The var form works anywhere, and you can combine it with a literal:
var sandwich = []string{"peanut butter", "jelly", "bread"}
Inside functions, := is the idiomatic choice.
Empty slices
A literal with no values, []int{}, is also empty with length 0, but unlike a var declaration it is not nil. For everyday work the two behave the same: you can loop over them, take their length and append to them. You only notice the difference when you compare against nil.
Slice or array: how to tell them apart
Look at the brackets. []string{...} is a slice. [3]string{...} is an array, and [...]string{"x", "y"} is an array whose length the compiler counts for you. A slice literal never has a number or ... between the brackets.
The difference matters when you copy. Assigning an array to another variable copies all its elements, while assigning a slice makes both variables refer to the same elements:
a := [3]int{50, 40, 30}
b := a
b[0] = 1
fmt.Println(a, b)
s := []int{50, 40, 30}
t := s
t[0] = 1
fmt.Println(s, t)
[50 40 30] [1 40 30]
[1 40 30] [1 40 30]
Changing b leaves a alone, but changing t also changes s. Keep this in mind whenever you pass a slice to a function.
The exercise
The lesson asks for two slices, each created with := and a literal.
fruitsis a[]stringholding"mango","kiwi"and"grapefruit", in that order.agesis a[]intholding14,32,50and21.
fruits := []string{"mango", "kiwi", "grapefruit"}
ages := []int{14, 32, 50, 21}
Strings need double quotes and numbers do not. Each value must match the element type: putting "14" into a []int is a compile error, because Go never converts between types silently.
Common mistakes
- Writing a length in the brackets.
[4]int{14, 32, 50, 21}is an array, not a slice, and you cannot append to it. - Using := outside a function. At the top level of a file, write
varinstead. - Leaving a variable unused. Go refuses to compile a program that declares a local variable and never uses it, so print a slice or read from it.
- Forgetting the braces.
[]intalone is only a type. The braces, even empty ones, create the value.
Key takeaways
- A slice type is
[]T, with no length in the brackets, and its size can change. var s []Tgives an empty slice;s := []T{a, b, c}gives one with values.- Arrays are copied on assignment; slices share their elements.
- Every element of a slice has the same type.