首页 > 后端开发 > Golang > 为什么 Go 的 `append` 函数在从范围循环追加指针时会产生意外的结果?

为什么 Go 的 `append` 函数在从范围循环追加指针时会产生意外的结果?

Patricia Arquette
发布: 2024-12-08 03:08:11
原创
151 人浏览过

Why Does Go's `append` Function Produce Unexpected Results When Appending Pointers from a Range Loop?

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中文网其他相关文章!

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板