理解Go中append的奇怪行为
在Go中,append函数对切片进行操作以添加新元素。但是,在 for range 循环中将指针附加到数组中的元素时,用户可能会遇到意外行为。
请考虑以下示例:
import "fmt" type Foo struct { val int } func main() { var a = make([]*Foo, 1) a[0] = &Foo{0} var 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) } }
预期输出:{0} {1} {2} {3}
实际输出:{0} {3} {3} {3}
该行为的原因
出现此意外行为是因为 for range 循环迭代元素的副本,而不是原始元素本身。在这种情况下,循环变量 e 保存数组当前元素的副本。附加切片时,会添加循环变量的地址,该地址为所有迭代引用相同的内存位置。因此,当遇到数组的最后一个元素时,所有附加地址都指向同一个元素。
修复
要解决此问题,append 函数应该是与原始数组元素的地址一起使用,而不是与循环变量一起使用。以下是更正后的代码:
for i := range b { a = append(a, &b[i]) }
经过此修改,输出将如预期:{0} {1} {2} {3}。
结论
理解 Go 中指针和非指针类型之间的区别对于正确处理内存引用至关重要。使用 for range 循环时,必须考虑是否需要访问原始元素还是副本,并相应地使用适当的语法。
以上是为什么在 Go `for...range` 循环中添加指针会产生意外结果?的详细内容。更多信息请关注PHP中文网其他相关文章!