gpt4 book ai didi

arrays - 奇怪的golang“append ”行为(覆盖 slice 中的值)

转载 作者:行者123 更新时间:2023-12-01 22:41:08 28 4
gpt4 key购买 nike

我有这个简单的代码:

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循环中,您使用副本而不是slice / array元素本身进行操作。for ... range复制其循环的元素,然后附加此临时循环变量的地址-在所有迭代中都相同。因此,您将相同的指针添加了3次。并且该临时变量将在上一次迭代(数组的最后一个元素)中设置为Foo{3},因此这就是为什么您看到该变量打印了3次的原因。
修复:不添加循环变量的地址,而是添加数组元素的地址:

for i := range b {
a = append(a, &b[i])
}
输出(在 Go Playground上尝试):
{0} {1} {2} {3} 
查看可能重复的 Assigned pointer field becomes <nil>
对此行为进行推理
在Go中,有指针类型和非指针类型,但是没有 "references"(在C++和Java中使用它的含义)。考虑到Go中没有“引用”类型的事实,这不是意外的行为。循环变量只是一个“普通”局部变量,它只能保存一个值(可以是指针或非指针),而不能保存引用。
摘自 this answer:

指针就是值,就像说 int数字一样。区别在于该值的解释:指针被解释为内存地址,而 int则被解释为整数。
当您想要更改 int类型的变量的值时,可以将指针传递给 int类型的 *int,然后修改指向的对象: *i = newvalue(分配的值是 int)。
指针也是如此:当您要更改指针类型 *int的变量的值时,您将指针传递给 *int类型的 **int,然后修改指向的对象: *i = &newvalue(分配的值是 *int)。

总而言之,循环变量只是具有您要循环的数组/ slice 的元素类型的普通变量,并且要使其具有实际迭代的值,必须将值赋给该变量,该值将复制该值。在下一次迭代中将覆盖它。

关于arrays - 奇怪的golang“append ”行为(覆盖 slice 中的值),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64013697/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com