首页 >后端开发 >Golang >为什么在 Go 的 `append` 函数中追加指针会导致意外覆盖?

为什么在 Go 的 `append` 函数中追加指针会导致意外覆盖?

Barbara Streisand
Barbara Streisand原创
2024-12-25 03:36:17750浏览

Why Does Appending Pointers in Go's `append` Function Lead to Unexpected Overwriting?

Go 的“append”函数出现意外覆盖问题

在 Go 中,append 函数经常用于用附加元素扩展切片。但是,有时,将指针附加到结构时可能会出现意外行为。

考虑以下代码片段:

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}。这种意外的行为源于 Go 行为的一个基本方面:

在 for Range 循环中进行复制

Go 使用 for range 循环迭代切片和数组,这会创建一个副本迭代过程中每个元素的值。在我们的代码中,for range 循环变量 e 表示数组元素 b[i] 的临时副本。不幸的是,我们随后将此临时变量的地址附加到切片 a。

修复

要解决此问题,我们需要附加原始数组元素而不是临时副本。通过修改 for 循环以使用索引 i,我们确保将正确的地址附加到切片:

for i := range b {
    a = append(a, &b[i])
}

此更改会产生 {0} {1} {2} {3 的预期输出}.

行为的原因

Go 缺乏真正的引用导致了这种情况 行为。在使用引用的 C 或 Java 中,循环变量将直接引用数组元素,从而允许通过循环变量进行更改。然而,在 Go 中,循环变量是一个不同的变量,它保存元素的副本,而不是引用。因此,对循环变量所做的更改不会反映在原始数组元素中。

以上是为什么在 Go 的 `append` 函数中追加指针会导致意外覆盖?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn