Loops Go范围循环范围和间接功能

Loops Go范围循环范围和间接功能,loops,go,scope,Loops,Go,Scope,有人能帮我解释一下我对golang循环范围和临时函数感到惊讶的原因吗?以下是一些更复杂代码的摘录: package main import ( "fmt" ) type Caller struct { call func() } func printer(val int) { fmt.Printf("the value is %v\n", val) } func main () { values := []int{1,2,3

有人能帮我解释一下我对golang循环范围和临时函数感到惊讶的原因吗?以下是一些更复杂代码的摘录:

package main

import ( "fmt" )

type Caller struct {
    call func()
}

func printer(val int) {
    fmt.Printf("the value is %v\n", val)
}

func main () {
    values := []int{1,2,3}

    var callers []Caller
    for _,val := range values {
        call := func() { printer(val) }
        callers = append(callers, Caller{call})
    }

    for _, caller := range callers {
        caller.call()
    }
}
这就产生了(对我来说)令人惊讶的结果:

the value is 3
the value is 3
the value is 3
如果我通过将range values循环体更改为以下内容来更改代码:

        theVal := val
        call := func() { printer(theVal) }
        callers = append(callers, Caller{call})
然后我们得到了最初希望的结果:

the value is 1
the value is 2
the value is 3

基本上,一个有效,另一个无效——我很清楚这一点,可以试着记住这个成语。我希望能有更多的了解,也许是在戈朗上一堂生活课。作用域规则和延迟执行意味着循环变量维护最终有效值并提交到循环期间构建的每个临时函数中,这意味着什么?为什么不将值“val”放入动态构建的func“call”中?我怀疑我对一些基本的东西感到困惑。即使看到一个工作版本,我也不确定我将来是否能够避免这样的陷阱。如果您有关于“为什么”迭代值会这样的建议,我很乐意听到(并提前感谢您)。

这也适用于您。这是来自网站的链接

主程序包
进口(
“fmt”
)
类型调用者结构{
调用func()
}
func打印机(val int){
fmt.Printf(“值为%v\n”,val)
}
func main(){
值:=[]int{1,2,3}
var调用者[]调用者
对于u,val:=范围值{
var call func()
func(v int){
call=func(){
打印机(v)
}
}(瓦尔)
调用者=追加(调用者,调用者{call})
}
对于_,调用者:=范围调用者{
caller.call()
}
}

另一种方法是在每个闭包启动时将val的当前值绑定到它,您可以将其存储在一个新变量中,然后使用它(您解决它的方法)。

请参阅gelang.org上的常见问题解答。循环只有一个变量,只有值改变。谢谢。我会记住的对于任何读者来说,在这个链接上:“人们可能会错误地期望看到a,b,c作为输出。你可能看到的是c,c,c。这是因为循环的每个迭代都使用变量v的同一个实例,所以每个闭包共享一个变量。”@Volker edit gelang.org to golang.org谢谢你,对于直接链接。@比尔,你能把它标记为已接受,这样社区就知道这个问题已经解决了吗?完成了,很抱歉。我仍然感兴趣的是,这适用于闭包;常见问题解答描述了并发性,但很明显,您不必运行并发程序就能遇到这种行为。