You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go遍历Map启动Goroutine时参数始终为最后迭代值的问题排查

Go遍历map启动Goroutine时参数始终为最后迭代值的修复方案

问题重现

原始代码

type Connection struct {
    Conn *somepackage.Conn // 示例中无需关注具体类型
    Channel chan []byte
}

var connectionMap map[string]map[string]Connection

...

for connID, conn := range connectionMap["someValue"] {
    fmt.Println(connID, conn)
    go func(c *Connection) {
        fmt.Println("inside fn", connID, c)
    }(&conn)
}

运行输出

6c2989b7-4e52-48b1-aa6f-60c03c4fe78a {0xc0002dc9a0 0xc0000309c0}
283560e8-2ade-431e-92e2-55751b825c67 {0xc0004f0000 0xc0004981e0}
inside fn 283560e8-2ade-431e-92e2-55751b825c67 &{0xc0004f0000 0xc0004981e0}
inside fn 283560e8-2ade-431e-92e2-55751b825c67 &{0xc0004f0000 0xc0004981e0}

问题:遍历map启动Goroutine时,connID和传入的conn指针最终都只显示最后一次迭代的值。

原因分析

Go的for range循环会复用同一个变量存储空间,循环里的connID和conn是同一个变量,每次迭代仅更新它们的值。而Goroutine启动后不会立即执行,当它们真正运行时循环可能已完成,此时这两个变量已被更新为最后一次迭代的值,因此所有Goroutine都会读取到最后一组值。

另外,代码中虽将&conn作为参数传入Goroutine,但conn本身是循环复用的变量,每次传入的都是同一个内存地址,最终指向最后一次迭代的conn值。

修复方案

有两种常用修复方式,核心都是让每个Goroutine绑定当前迭代的独立值副本:

方式一:循环内创建局部变量保存当前迭代值

在每次迭代时,将当前的connID和conn赋值给局部变量,让Goroutine捕获这些独立的局部变量:

for connID, conn := range connectionMap["someValue"] {
    fmt.Println(connID, conn)
    // 创建局部变量保存当前迭代的独立值
    currentID := connID
    currentConn := conn
    go func(c *Connection) {
        fmt.Println("inside fn", currentID, c)
    }(&currentConn)
}

方式二:将迭代值作为参数传递给Goroutine

把connID也作为参数传入Goroutine,确保每个Goroutine拿到当前迭代的副本:

for connID, conn := range connectionMap["someValue"] {
    fmt.Println(connID, conn)
    // 将connID和conn都作为参数传入Goroutine
    go func(id string, c *Connection) {
        fmt.Println("inside fn", id, c)
    }(connID, &conn)
}

验证效果

修复后运行,输出会变为:

6c2989b7-4e52-48b1-aa6f-60c03c4fe78a {0xc0002dc9a0 0xc0000309c0}
283560e8-2ade-431e-92e2-55751b825c67 {0xc0004f0000 0xc0004981e0}
inside fn 6c2989b7-4e52-48b1-aa6f-60c03c4fe78a &{0xc0002dc9a0 0xc0000309c0}
inside fn 283560e8-2ade-431e-92e2-55751b825c67 &{0xc0004f0000 0xc0004981e0}

每个Goroutine都会输出对应迭代的connID和conn值。

内容的提问来源于stack exchange,提问作者Shiva T. Kota

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 06:15:55