为什么我们需要在这里复制 u 的值?

我是 Go 的初学者,正在学习以这段代码为例的在线课程:



func ConcurrentMutex(url string, fetcher Fetcher, f *fetchState) {

    var done sync.WaitGroup


    for _, u := range urls {

        done.Add(1)

        u2 := u

        go func() {

            defer done.Done()

            ConcurrentMutex(u2, fetcher, f)

        }()

        //go func(u string) {

        //  defer done.Done()

        //  ConcurrentMutex(u, fetcher, f)

        //}(u)

    }


    done.Wait()

    return

}




u 的类型是字符串,在我看来,我们应该能够将 u 传递给内部函数中的 ConcurrentMutex 调用,而无需将其值复制到 u2。然而,教授坚持认为,Go 内存模型意味着当我们不断改变 u 的值时,它会影响对 ConcurrentMutex 的不同调用。


我仍然不完全确定为什么。调用函数时的 u 值不应该传递给函数吗?如果我们传递一个指针,我会理解的,但因为我们不是,这让我感到困惑。


有人可以解释一下 Go 的内存模型是如何解释这个块的吗?


注意:注释掉的内部函数是讲座视频中示例中使用的原始函数,但在讲座笔记中进行了更改。在我看来两者都是等价的,所以我想这个问题适用于两者。


莫回无
浏览 114回答 1
1回答

喵喵时光机

您正在使用的是关闭。u2 在内部函数和围绕它的函数之间共享。这意味着随着 u2 的每次迭代被修改,修改后的值对内部函数可见。更好的编写方式是使用已注释掉的代码。通过显式地将值传递给 goroutine,您可以确保 goroutine 携带它自己的副本,该副本不会被周围的函数修改。Go 规范对此有何评论:Go 规范函数文字 函数文字表示匿名函数。FunctionLit = "func" 签名 FunctionBody 。func(a, b int, z float64) bool { return a*b < int(z) } 函数字面量可以分配给变量或直接调用。f := func(x, y int) int { return x + y } func(ch chan int) { ch <- ACK }(replyChan) 函数字面量是闭包:它们可以引用在周围函数中定义的变量。然后,这些变量在周围的函数和函数字面量之间共享,只要它们可以访问,它们就会继续存在。希望这能回答你的问题。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go