Golang slice append return value? [SOLVED]

In the previous chapter, we discuss how to use append function in Golang. append is a built-in function which appends elements to the end of a slice. If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated. Append returns the updated slice. It is therefore necessary to store the result of append, often in the variable holding the slice itself.

The signature of append:

Advertisement
func append(slice []T, elements ...T) []T

where T is a placeholder for any given type. You can't actually write a function in Go where the type T is determined by the caller. That's why append is built in: it needs support from the compiler.

Golang slice append return value? [SOLVED]

 

Example 1: Simple usage of append function

Here is an example of using append 1 or multiple elements to a slice:

package main

import "fmt"

func main() {
	slice0 := []int{2, 5,13,15}
	fmt.Println("slice 0:", slice0)
     // append 1 element
	fmt.Println("after the first append:", 	append(slice0, 4))
	// append multiple elements
	fmt.Println("after the second append:", append(slice0, 3, 5, 7))
}

Output

slice 0: [2 5 13 15]
after the first append: [2 5 13 15 4]
after the second append: [2 5 13 15 3 5 7]

What append does is append the elements to the end of the slice and return the result. The result needs to be returned because, as with our hand-written Append, the underlying array may change. You can see that the original slice is not affected after the first append because we do not assign return append value to the original slice.

 

Example 2: Update the slice itself after calling append function

In the example below, we will assign the return append value to the original slice:

package main

import "fmt"

func main() {
	slice0 := []int{2, 5,13,15}
	fmt.Println("slice 0:", slice0)
     // append 1 element
	slice0 = append(slice0, 4)
	fmt.Println("after the first append:", slice0)
	// append multiple elements
	slice0 = append(slice0, 3, 5, 7) 
	fmt.Println("after the second append:", slice0)
}

Output:

Advertisement
slice 0: [2 5 13 15]
after the first append: [2 5 13 15 4]
after the second append: [2 5 13 15 4 3 5 7]

 

Example 3: Unintended side effects when using append function

In this example, we will first create an int slice:

firstSlice := []int{12, 6, 19, 98}

Do the following steps:

  • Initialize a new slice (secondSlice) which contains the first three elements of the firstSlice (firstSlice[:3]) and appending 1 element to it.
  • Initialize a new slice (thirdSlice) by appending 1 element to the firstSlice
secondSlice := append(firstSlice[:3], 59)
thirdSlice := append(firstSlice, 820)

Now we will print out these 3 slices:

package main

import "fmt"

func main() {
	firstSlice := []int{12, 6, 19, 98}
	secondSlice := append(firstSlice[:3], 59)
	thirdSlice := append(firstSlice, 820)

	fmt.Println("the first slice:", firstSlice)
	fmt.Println("the second slice:", secondSlice)
	fmt.Println("the third slice", thirdSlice)
}

Output:

the first slice: [12 6 19 59]
the second slice: [12 6 19 59]
the third slice [12 6 19 59 820]

The output of the secondSlice is easy to understand. But how about the firstSlice and thirdSlice? You may think that the firstSlice is not affected by the append function call. But why both firstSlice and thirdSlice are changed?

You must first understand the proper definition of a slice in order to comprehend this behavior. Slices hold references to an underlying array, and if you assign one slice to another, both refer to the same array. The length of a slice may be changed as long as it still fits within the limits of the underlying array; just assign it to a slice of itself. The capacity of a slice, accessible by the built-in function cap, reports the maximum length the slice may assume.

In other words, the underlying array will not be assigned to new memory address if it can fit the additional element(s). In the case of there is insufficient capacity, a new array will be made. Now you can understand why the firstSlice is affected by the append function (because both firstSlice and secondSlice refer to 1 underlying array).

 

Summary

The idea of appending to a slice is so useful it's captured by the append built-in function. We must return the slice afterwards because, although Append can modify the elements of slice, the slice itself (the run-time data structure holding the pointer, length, and capacity) is passed by value.

 

References

https://pkg.go.dev/builtin#append
https://go.dev/doc/effective_go#append

 

Categories GO

Didn't find what you were looking for? Perform a quick search across GoLinuxCloud

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment

X