Dictionary 为什么这两个for循环变量给了我不同的行为?

Dictionary 为什么这两个for循环变量给了我不同的行为?,dictionary,for-loop,go,closures,slice,Dictionary,For Loop,Go,Closures,Slice,我在我的程序中看到了与我的程序中的这个特定循环相关的不同行为,但我不确定我是否理解它为什么会以这种方式运行 //全局变量 var cmds=[]字符串{ “创建”, “删除”, “更新”, } func loop1(){ 操作:=make(映射[string]func()) 对于,cmd:=范围cmds{ 动作[cmd]=func(){ 格式打印LN(cmd) } } 对于u,动作:=范围动作{ 行动() } } func loop2(){ 操作:=make(映射[string]func())

我在我的程序中看到了与我的程序中的这个特定循环相关的不同行为,但我不确定我是否理解它为什么会以这种方式运行

//全局变量
var cmds=[]字符串{
“创建”,
“删除”,
“更新”,
}
func loop1(){
操作:=make(映射[string]func())
对于,cmd:=范围cmds{
动作[cmd]=func(){
格式打印LN(cmd)
}
}
对于u,动作:=范围动作{
行动()
}
}
func loop2(){
操作:=make(映射[string]func())
对于i,cmd:=范围cmds{
命令:=cmds[i]
动作[cmd]=func(){
fmt.Println(命令)
}
}
对于u,动作:=范围动作{
行动()
}
}
loop1()
的输出为

update
update
update
delete
update
create
loop2()
的输出为

update
update
update
delete
update
create
我去看报纸,读了下面的内容

在切片上进行测距时,每次迭代都返回两个值。第一个是索引,第二个是该索引处元素的副本


它表示一个副本,那么这是否意味着它返回字符串的副本,但它实际上是指向变量
cmd
的指针?在这种情况下,任何对
cmd
的引用都将在循环结束时实际引用数组中的最后一个元素,例如
update
?这是否意味着在使用
range
方法时,数组的元素应该始终由它们的索引引用,并且由于它总是更新指针,所以使用它返回的元素的用例是什么是指在引用循环变量
cmd
actions
映射中存储函数文本。此循环变量只有一个实例,因此在循环后调用
操作
映射中存储的函数时,所有函数都将引用此单个循环变量(保留此变量是因为函数/闭包仍有对它的引用),但是它在执行时的值将是
for
循环设置的最后一个值,这是
cmds
切片中的最后一个值(即
“更新”
,因此您将看到
“更新”
打印了3次)

一个简单的解决方法是复制这个循环变量,因此每次迭代,每个函数文本都有自己的副本,它与循环变量“分离”:

func loop1() {
    actions := make(map[string]func())

    for _, cmd := range cmds {
        cmd2 := cmd
        actions[cmd] = func() {
            fmt.Println(cmd2) // Refer to the detached, copy variable!
        }
    }
    for _, action := range actions {
        action()
    }
}
使用此选项,可以输出
loop1()
(在上尝试):

这不是关于。。。范围,这是因为闭包引用同一个变量,并且您不会立即使用变量的值,只在循环之后使用。当你打印这个变量的值时,所有人都打印它的最后一个值


还可以看到这个可能的重复:

Ok,这与我们使用闭包这一事实有关,闭包不一定与
范围有关operation@sreya是的,这不是关于。。。范围
,这是因为闭包引用了同一个变量,当你打印这个变量的值时,所有人都会打印它的最后一个值。或者对于更干净的代码,只需将变量作为参数传递给闭包:
actions[cmd]=func(cmd string){fmt.Println(cmd)}(cmd)
@Adrian通常是,但在这种情况下,该命令是一种没有参数的函数类型,因此以这种方式使用它会更加不方便