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

为何在Goroutine中传递函数作参数时变量值有时不符合预期

问题分析:Go闭包的变量捕获机制

先看你贴的代码:

import (
    "fmt"
    "time"
)

func WithRecover(r func()) {
    r()
}

func printRewardAmount(rewardAmount int) {
    fmt.Println(rewardAmount)
}

func main() {
    var rewardAmount int
    rewardAmount = 1
    go WithRecover(func() { printRewardAmount(rewardAmount) })
        if true {
        rewardAmount = 2
        }
    time.Sleep(100 * time.Millisecond)
}

你以为rewardAmount是值传递所以输出应该是1,但实际偶尔会得到2,核心原因是闭包捕获的是变量的引用,不是变量的当前值。

  • main函数里的rewardAmount是一个栈变量,匿名函数func() { printRewardAmount(rewardAmount) }作为闭包,并没有在创建时复制rewardAmount的数值1,而是保存了指向这个变量的引用。
  • goroutine启动后和main goroutine并发执行,main里的代码执行速度极快,几乎会立刻把rewardAmount改成2。当goroutine里的闭包最终执行printRewardAmount(rewardAmount)时,它会读取rewardAmount的当前值——这时候大概率已经是2了。
  • 偶尔输出1只是因为goroutine的调度碰巧比main里的rewardAmount = 2执行得快,但这种情况完全不可靠,属于典型的竞态条件。

如果要确保输出1,需要在创建闭包时就把当前值传递进去,比如修改成这样:

go WithRecover(func(amount int) { printRewardAmount(amount) }(rewardAmount))

这样会把当时的rewardAmount值1作为参数传给匿名函数,形成值传递,后续修改rewardAmount不会影响这个参数的值。

内容的提问来源于stack exchange,提问作者dev1417

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 22:57:39