【问题标题】:Go channel with pointer value doesn't behave as expected in for loop [duplicate]带有指针值的 Go 通道在 for 循环中的行为不符合预期[重复]
【发布时间】: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

【问题讨论】:

  • 除非有令人信服的理由,否则不要在频道上发送指针。通道写入将是 goroutine 安全的,但对该指针的并发写入则不会。
  • @colm.anseo 谢谢,我知道:D

标签: loops go channel


【解决方案1】:

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

for _, d := range data {
    d := d
    chanA <- str1{stringA: &d}
}

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

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

【讨论】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    • 2016-02-23
    • 2010-10-23
    • 2016-10-08
    相关资源
    最近更新 更多