本文介绍了为什么这两个for循环变体给我不同的行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

我看到程序中的不同行为与我的程序中的特定循环有关,但我不确定我是否明白为什么它的行为如此。

    loop1()在动作映射中引用循环变量  cmd 的函数文字。这个循环变量只有一个实例,所以当循环后面调用存储在 action 映射中的函数时,所有的都会引用这个循环变量(它保留因为函数/闭包仍然有对它的引用),但是它在执行时的值将是由为设置的最后一个值。循环,它是 cmds 切片(即,update)中的最后一个值,所以您会看到update打印3次)。

一个简单的解决方法是复制这个循环变量,每一次迭代,每个函数文字都会有自己的副本,从循环变量中分离出来:

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

for _,cmd:= range cmds {
cmd2:= cmd
actions [cmd ] = func(){
fmt.Println(cmd2)//引用分离的复制变量!
}
}
for _,action:= range actions {
action()
}
}

有了这个, loop1()的输出(试一下):

  update 
create
delete

这不是问题 for ... range ,这是因为闭包引用的是同一个变量,并且只在循环之后才使用变量的值。当你打印这个变量的值时,所有打印出来的都是相同的最后一个值。



另见下面这个可能的重复:


I'm seeing different behavior in my program that's tied to this particular loop in my program but I'm not sure I understand why it's behaving the way it is.

//global variable
var cmds = []string {
    "create",
    "delete",
    "update",
}

func loop1() {

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

    for _, cmd := range cmds {
        actions[cmd] = func() {
            fmt.Println(cmd)
        }
    }
    for _, action := range actions {
        action()
    }
}
func loop2() {

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

    for i, cmd := range cmds {
        command := cmds[i]
        actions[cmd] = func() {
            fmt.Println(command)
        }
    }
    for _, action := range actions {
        action()
    }
}

The output for loop1() is

update
update
update

The output for loop2() is

delete
update
create

I went looking on the internet and read the following

It says a copy, so does that mean it returns a copy of the string but it's really a pointer to variable cmd? In which case any references to cmd will by the end of the loop all actually reference the last element in the array, e.g. update? Does this mean that elements of an array should always be referenced by their index when using the range method, and what's the use case for using the element it returns since it's always updating the pointer?

解决方案

The problem with loop1() is that you store a function literal in the actions map that references the loop variable cmd. There is only one instance of this loop variable, so when after the loop you call the functions stored in the actions map, all will refer to this single loop variable (which is kept because the functions / closures still have a reference to it), but its value at the time of execution will be the last value set by the for loop, which is the last value in the cmds slice (that is, "update", so you'll see "update" printed 3 times).

An easy workaround is to make a copy of this loop variable, so each iteration, each function literal will have its own copy, which is "detached" from the loop variable:

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()
    }
}

With this, output of loop1() (try it on the Go Playground):

update
create
delete

This it's not an issue of the for ... range, it's because the closures refer to the same variable, and you don't use the value of the variable right away, only after the loop. And when you print the value of this variable, all print the same, last value of it.

Also see this possible duplicate: Golang: Register multiple routes using range for loop slices/map

这篇关于为什么这两个for循环变体给我不同的行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-06 09:23