Home > Article > Backend Development > Why do slices appended in a loop exhibit unexpected behavior when creating new slices in Go?
Unexpected Slice Append Behavior in Go
In the realm of Go programming, an unusual behavior has been encountered when appending elements to a slice within a loop and subsequently trying to create new slices based on the loop's result. Intriguingly, the last append operation overrides the slices created from previous appends.
Exploring the Issue
Consider the following code snippet:
<code class="go">func create(iterations int) []int { a := make([]int, 0) for i := 0; i < iterations; i++ { a = append(a, i) } return a }</code>
When calling create(11) and creating new slices by appending elements to it (i.e., j := append(i, 100), g := append(i, 101), h := append(i, 102)), one would expect the last elements of these slices (j, g, and h) to be 100, 101, and 102, respectively. However, surprisingly, in this case, all of them end up being 102.
This behavior stands in stark contrast to what happens when creating new slices from a slice literal, as demonstrated below:
<code class="go">func sliceFromLiteral() { i := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} j := append(i, 100) g := append(i, 101) h := append(i, 102) fmt.Printf("i: %v\nj: %v\ng: %v\nh:%v\n", i, j, g, h) }</code>
In this case, j, g, and h exhibit the expected behavior, with last elements being 100, 101, and 102, respectively.
Delving into the Root Cause
To unravel the mystery behind this unexpected behavior, it's crucial to understand that the appending operation not only modifies the underlying array but also returns a new slice. This implies that the slices j, g, and h are in fact pointing to the same underlying array. Hence, when the last append (append(i, 102)) is performed, it modifies the last element of the underlying array, effectively overriding the values in j, g, and h.
The Idiomatic Solution
To avoid this unexpected behavior, it's imperative to copy the slice before attempting any appends. Doing so creates a new underlying array, ensuring that the original slice remains unmodified. The following code exemplifies the idiomatic way of creating multiple new slices based on existing ones:
<code class="go">func makeFromSlice(sl []int) []int { result := make([]int, len(sl)) copy(result, sl) return result }</code>
By employing this approach, one can effortlessly create new slices while preserving the integrity of the original data.
The Slice Literal Exception
The peculiar behavior observed with slices created from loops does not extend to slices initialized from literals. This is attributable to the fact that Go allocates a new array if an append operation would exceed the capacity of the backing array. This behavior is independent of whether the slice is created from a literal or a variable and is merely a consequence of how arrays are handled internally in Go.
The above is the detailed content of Why do slices appended in a loop exhibit unexpected behavior when creating new slices in Go?. For more information, please follow other related articles on the PHP Chinese website!