Start learning free

LESSON 89 OF 338 · ARRAYS I

Slices in Go: Creating Resizable Arrays

Lesson Read the full explanation

A big limitation of static arrays in Go is the fact that once the array is created, it has a fixed size.

The slice overcomes this limitation by having variable size and allowing for elements to be added or removed.


Creation:

You declare a slice by specifying the element type prefixed with [], along with the name of the slice:

var sandwich []string

This code creates an empty slice named sandwich where each item is a string.


Initialization I:

You can also initialize a slice at declaration by using := with a slice literal — an opening bracket, end it with a closing bracket, and put a comma between each entry, like this:

sandwich := []string{"peanut butter", "jelly", "bread"}

We created a slice named sandwich which consits of 3 items: "peanut butter", "jelly" and "bread".


Initialization II:

Another way of initializing a slice at declaration is by listing all elements explicitly in a slice literal, like this:

animals := []string{"cat", "cat", "cat", "cat", "cat"}

We created a slice named animals which consits of 5 "cat" items.


Assignment
Follow the Coding Tutorial and let's create some slices!


Hint
Look at the examples above if you get stuck.


STEP 1 OF 2
    Ctrl + Enter to check

    GO · ARRAYS I

    Arrays in Go, explained

    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.

    1. fruits is a []string holding "mango", "kiwi" and "grapefruit", in that order.
    2. ages is a []int holding 14, 32, 50 and 21.
    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 var instead.
    • 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. []int alone 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 []T gives 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.
    Keep going with GoAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free