2 回答
TA贡献1880条经验 获得超4个赞
您肯定是指创建循环变量的副本。通常,在此代码中:
for i := 0; i < 100; i++ {
go func() {
fmt.Println(i)
}
}
i将在所有 goroutines 中引用循环变量,所以如果 goroutines 产生,然后循环在它们调用之前继续运行fmt.Println(i),i当它们调用它时将与它们从循环中产生时不同。正如你提到的,解决这个问题的一种方法是:
for i := 0; i < 100; i++ {
i := i
go func() {
fmt.Println(i)
}
}
添加的行i := i引入了一个名为 的局部变量i,并将其设置为等于循环变量i。这是两个不同的变量。你还不如说j := i然后用j。我倾向于认为使用i := i更令人困惑,但有些人更喜欢它。在任何情况下,鉴于它是一个局部变量,每个循环都有一个不同的实例,这意味着每个 goroutine 都会看到它自己的唯一实例,不会被更改。
虽然这个习语可以在Effective Go 中找到(在页面上搜索“req := req”),但让我澄清一些事情:这是令人困惑的,应该避免。我不知道为什么 Go 作者认为引入这个习语是个好主意,在我看来,应该避免。为什么?因为有一种更简洁的方法可以完成更容易理解的相同事情:
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
}(i)
}
在这个版本中,匿名函数接受一个整数参数,当它在 goroutine 中产生时,循环变量i作为该参数传递。人们对这些语义有了更扎实的理解,因此更容易看到它的作用并理解它为什么起作用。如果这仍然令人困惑,我建议更改参数名称:
for i := 0; i < 100; i++ {
go func(j int) {
fmt.Println(j)
}(i)
}
我认为这两种方法更容易理解,应该使用而不是您提到的示例。
TA贡献1827条经验 获得超9个赞
你的意思是这样的构造:
func foo() {
var bar // some variable
go func() {
bar := bar // copy bar into inner scope
}()
}
- 2 回答
- 0 关注
- 186 浏览
添加回答
举报