带有指针值的 Go 通道在 for 循环中的行为不符合预期[重复]

Posted

技术标签:

【中文标题】带有指针值的 Go 通道在 for 循环中的行为不符合预期[重复]【英文标题】:Go channel with pointer value doesn't behave as expected in for loop [duplicate] 【发布时间】:2021-12-07 13:12:54 【问题描述】:

我有一个问题,当从切片中对源进行测距时,我的通道中的数据在下游接收器中发生了更改,我不确定为什么会出现这种情况: https://play.golang.org/p/fPZJRj6XTRO

import (
    "fmt"
)

func main() 
    fmt.Println("Hello, playground")

    chanA := make(chan *string)

    go func() 
        data := []string
            "A",
            "B",
            "C",
        
        for _, d := range data 
            chanA <- &d
        
        close(chanA)
    ()

    for res := range chanA 
        fmt.Println(*res)
    

结果:

 Hello, playground
 B
 B
 C

预期:

 Hello, playground
 A
 B
 C

【问题讨论】:

golang.org/doc/faq#closures_and_goroutines 除非有令人信服的理由,否则不要在频道上发送指针。通道写入将是 goroutine 安全的,但对该指针的并发写入则不会。 @colm.anseo 谢谢,我知道:D 【参考方案1】:

您正在获取循环变量d 的地址。虽然地址保持不变,但循环变量的值在迭代之间会发生变化。当主程序取消引用指针时,它将获得循环变量的(有些随机的)当前值。要解决此问题,请在循环内复制变量:

for _, d := range data 
    d := d
    chanA <- str1stringA: &d

:= 为循环的每次迭代创建一个新变量。

完整代码在这里:https://play.golang.org/p/kCD140I04_r

【讨论】:

这有帮助,谢谢,但从技术上讲,变量的地址在迭代之间改变会更准确吗? @EatonEmmerich 哦,是的,你当然是对的。我将添加更多文字以明确更改的是值而不是地址。【参考方案2】:

变量 d 不会在每次迭代中重新声明,因此它需要一个新变量作为 for 循环中内容的副本,即:

for _, d := range data 
   d2 := d
   chanA <- &d2

【讨论】:

以上是关于带有指针值的 Go 通道在 for 循环中的行为不符合预期[重复]的主要内容,如果未能解决你的问题,请参考以下文章

C语言中带有指针的for循环

我如何使用指针摆脱复制矩阵值的四个循环?

如何在go中使用带有for循环的列表

我的Go语言学习之旅三:Go语言中的for循环

地图是通过价值或Go中的参考传递的吗?

go语言,为啥range循环取的指针地址和直接用数组取的指针地址不一样,求指教