在循环中覆盖了封闭变量

huangapple go评论88阅读模式
英文:

Enclosed Variable Overridden In Loop

问题

我正在尝试构建一个包含封闭变量(在这种情况下是一个字符串)的函数数组,但是我得到了一些意外的输出。我猜想我得到这个输出的原因是每次迭代后,被附加的函数文字实际上是一个指向正在更改的代码的指针。

有没有办法使用new()make()创建一个函数类型,以便append()在每次迭代时都获得一个不同的函数实例?

package main

import "log"

var functions []func()

func main() {
    for _, s := range [...]string{"goodbye", "cruel", "world"} {
        functions = append(functions, func() {
            log.Println(s)
        })
    }
    for _, f := range functions {
        f()
    }
}

输出:

2014/11/23 18:13:16 world
2014/11/23 18:13:16 world
2014/11/23 18:13:16 world
英文:

I am trying to build an array of functions that contain an enclosed variable (in this case a string) but I was getting some unexpected output. I figure the reason I am getting this output is because the func literal being appended is actually a pointer to code that is being changed after each iteration.

Is there a way to new() or make() a function type so that append() will get a different function instance per iteration instead?

package main

import "log"

var functions []func()

func main() {
	for _, s := range [...]string{"goodbye", "cruel", "world"} {
		functions = append(functions, func() {
			log.Println(s)
		})
	}
	for _, f := range functions {
		f()
	}
}

Outputs:

2014/11/23 18:13:16 world
2014/11/23 18:13:16 world
2014/11/23 18:13:16 world

答案1

得分: 3

每次循环迭代都使用相同的变量s实例,因此每个闭包共享该单个变量。为了将s的当前值绑定到每个闭包中,需要修改内部循环以在每次迭代时创建一个新变量。例如,

package main

import "log"

var functions []func()

func main() {
    for _, s := range [...]string{"goodbye", "cruel", "world"} {
        s := s // 创建新的s
        functions = append(functions, func() {
            log.Println(s)
        })
    }
    for _, f := range functions {
        f()
    }
}

输出:

2009/11/10 23:00:00 goodbye
2009/11/10 23:00:00 cruel
2009/11/10 23:00:00 world

参考资料:

What happens with closures running as goroutines?

Captured Closure (for Loop Variable) in Go

英文:

Each iteration of the loop uses the same instance of the variable s, so each closure shares that single variable. To bind the current value of s to each closure as it is launched, one must modify the inner loop to create a new variable each iteration. For example,

package main

import "log"

var functions []func()

func main() {
	for _, s := range [...]string{"goodbye", "cruel", "world"} {
		s := s // create new s
		functions = append(functions, func() {
			log.Println(s)
		})
	}
	for _, f := range functions {
		f()
	}
}

Output:

<pre>
2009/11/10 23:00:00 goodbye
2009/11/10 23:00:00 cruel
2009/11/10 23:00:00 world
</pre>

References:

What happens with closures running as goroutines?

Captured Closure (for Loop Variable) in Go

huangapple
  • 本文由 发表于 2014年11月24日 10:22:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/27096978.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定