Start learning free

LESSON 97 OF 338 · ARRAYS I

Appending to a Slice in Go: The append Function

Lesson Read the full explanation

We can add elements to the end of a slice using the built-in append() function.

append() takes the slice and one or more new values, and returns a new slice with those values added to the end:

arr1 := []int{1, 2, 3}
arr1 = append(arr1, 4)

// arr1 is now {1, 2, 3, 4}

Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 2
    Ctrl + Enter to check

    GO · ARRAYS I

    Array Push in Go, explained

    Adding to the end

    Go has no push method on slices. You add elements to the end with the built-in function append. It takes a slice and one or more values, and returns a slice with the values added:

    arr1 := []int{1, 2, 3}
    arr1 = append(arr1, 4)
    fmt.Println(arr1)
    
    [1 2 3 4]
    

    Notice the assignment: arr1 = append(arr1, 4). The result must be stored. Calling append(arr1, 4) on its own line does not compile, and the compiler reports that the value of append is not used.

    Why the result must be stored

    A slice refers to an underlying array of a certain capacity. If there is spare room, append writes the new value there and returns a slice that is one element longer. If the array is full, append allocates a bigger array, copies the elements over and returns a slice that refers to the new array. Your old variable still describes the old slice, with its old length, so only the returned value is up to date.

    That is also why appending to a nil slice works. A slice declared with var s []string starts empty, and appending to it builds it up:

    var s []string
    for i := 0; i < 3; i++ {
    	s = append(s, fmt.Sprint("item", i))
    }
    fmt.Println(s)
    
    [item0 item1 item2]
    

    Several values at once

    append accepts any number of values, which are added in the order you list them. To add all the elements of another slice, follow it with ...:

    arr1 = append(arr1, 5, 6)
    more := []int{7, 8}
    arr1 = append(arr1, more...)
    fmt.Println(arr1, len(arr1))
    
    [1 2 3 4 5 6 7 8] 8
    

    The exercise

    You start with these slices:

    fruits := []string{"mango", "kiwi", "grapefruit"}
    ages := []int{14, 32, 50, 21}
    
    1. Append "apple" to fruits. It goes at the end, as the fourth fruit.
    2. Append 10 and then 23 to ages, with two calls. The order matters, because each value lands after the previous one.
    fruits = append(fruits, "apple")
    ages = append(ages, 10)
    ages = append(ages, 23)
    

    Afterwards fruits is [mango kiwi grapefruit apple] and ages is [14 32 50 21 10 23]. A single call, append(ages, 10, 23), would give the same result.

    A gotcha: sharing after append

    Because a slice shares its array, two slices built from the same one can interfere when there is spare capacity:

    c := make([]int, 3, 5)
    d := append(c, 9)
    e := append(c, 8)
    fmt.Println(d, e)
    
    [0 0 0 8] [0 0 0 8]
    

    Both appends wrote into the same spare slot, so d changed when e was created. When the array is full, append copies, and the slices stay separate. Code should not depend on either case: after x = append(x, v), treat the new x as the only valid name for the data.

    Cost

    Appending one element is cheap on average. When the array fills up, Go allocates a larger one, roughly doubling at small sizes, and copies the elements across. Growing a slice of n elements by repeated appends therefore takes O(n) time overall, so appending in a loop is fine.

    You can watch this with cap. Appending the numbers 0 to 19 one at a time to an empty []int and printing the capacity each time it changed gave 1, 2, 4, 8, 16 and 32 in this Go version. The exact growth rule is an implementation detail, so do not rely on those numbers in your own code. Know only that each reallocation copies the elements, and that a slice you build in a loop does not need to be sized in advance.

    Common mistakes

    • Dropping the result. append(ages, 10) alone does not compile.
    • Appending to an array. Only slices can be appended to. An array such as [4]int has a fixed size.
    • Appending the wrong type. The values must match the element type: you cannot append "10" to a []int.
    • Expecting insertion at the front. append only adds at the end.

    Key takeaways

    • s = append(s, v) adds v at the end; always assign the result.
    • Several values can be appended in one call, and other... appends a whole slice.
    • A nil slice is a fine starting point.
    • Appending in a loop is efficient on average.
    Keep going with GoAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free