Unintended Overwriting in Go's "append" Function
In Go, exploring the nuances of appending to slices can sometimes lead to unexpected outcomes. Let's delve into an example that showcases this behavior.
Consider the following code:
import "fmt" type Foo struct { val int } func main() { a := make([]*Foo, 1) a[0] = &Foo{0} b := [3]Foo{Foo{1}, Foo{2}, Foo{3}} for _, e := range b { a = append(a, &e) } for _, e := range a { fmt.Printf("%v ", *e) } }
Intriguingly, instead of printing {0} {1} {2} {3}, the output reads as {0} {3} {3} {3}. To unravel this puzzle, let's dissect the "append" function.
In Go, "append" expects a pointer to the slice to which we are adding elements. In our example, we correctly store pointers to "Foo" instances in the slice "a."
However, when looping through the elements of the array "b," we encounter a subtle issue. The "range" syntax iterates over a copy of each element rather than the actual element itself. As a result, we are consistently adding pointers to copies of the "Foo" instance "e," which points to "Foo{3}" in the final iteration.
To correct this behavior, we need to reference the actual elements of "b" in our "append" operation:
for i := range b { a = append(a, &b[i]) }
This modification ensures we add pointers directly to the elements within "b," resulting in the desired output: {0} {1} {2} {3}.
Understanding the underlying reason for this behavior is crucial. In Go, pointers are values, interpreted as memory addresses when manipulating data. As such, "range" loops iterate over copies of values rather than the original objects. This knowledge aids in understanding why in our initial code, three elements pointed to the same "Foo{3}" instance.
The above is the detailed content of Why Does Go's `append` Function Produce Unexpected Results When Appending Pointers from a Range Loop?. For more information, please follow other related articles on the PHP Chinese website!