Go 的“append”函数中的意外覆盖
在 Go 中,探索附加到切片的细微差别有时会导致意想不到的结果。让我们深入研究一个展示此行为的示例。
考虑以下代码:
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) } }
有趣的是,输出不是打印 {0} {1} {2} {3}读作 {0} {3} {3} {3}。为了解开这个谜题,让我们剖析“append”函数。
在 Go 中,“append”需要一个指向我们要添加元素的切片的指针。在我们的示例中,我们正确地将指向“Foo”实例的指针存储在切片“a”中。
但是,当循环遍历数组“b”的元素时,我们遇到了一个微妙的问题。 “范围”语法迭代每个元素的副本而不是实际元素本身。因此,我们不断添加指向“Foo”实例“e”副本的指针,该实例在最终迭代中指向“Foo{3}”。
要纠正此行为,我们需要引用“append”操作中“b”的实际元素:
for i := range b { a = append(a, &b[i]) }
此修改可确保我们直接将指针添加到“b”中的元素,从而产生所需的输出:{0} {1} {2} {3}。
了解此行为的根本原因至关重要。在 Go 中,指针是值,在操作数据时解释为内存地址。因此,“范围”循环迭代值的副本而不是原始对象。这些知识有助于理解为什么在我们的初始代码中,三个元素指向同一个“Foo{3}”实例。
以上是为什么 Go 的 `append` 函数在从范围循环追加指针时会产生意外的结果?的详细内容。更多信息请关注PHP中文网其他相关文章!