英文:
Passing a pointer inside a loop with anonymous go functions causes only last element pointer to be used
问题
在下面的代码中,我正在传递指向匿名Go函数的指针,但代码的行为并不符合我的预期。
package main
import "fmt"
type (
Element struct{
Name string
}
)
func main() {
elements := []Element{{"first"}, {"second"}, {"third"}, {"fourth"}}
waiting := make(chan bool)
for _, element := range elements {
go func(element *Element){
fmt.Println("Element Name: ", element.Name)
waiting <- true
}(&element)
}
for i := 0; i < 4; i++{
<- waiting
}
}
我期望代码输出:
- 'first'
- 'second'
- 'third'
- 'fourth'
但实际上它打印出:
- 'fourth'
- 'fourth'
- 'fourth'
- 'fourth'
所以看起来匿名go函数将其*Element参数“解析”为在那个循环中的任何内容,因此通过传递Element{}本身而不是指向元素的指针来修复此代码。
我的问题是:
- 这是定义好的行为吗?
- 我该如何重写代码以接受指向我的Element{}的指针?
Playground:
http://play.golang.org/p/tcRvforQE4
编辑:问题格式化
英文:
So in the following code I'm passing pointers to anonymous go functions but the code is not behaving as I am expecting it to do.
package main
import "fmt"
type (
Element struct{
Name string
}
)
func main() {
elements := []Element{{"first"}, {"second"}, {"third"}, {"fourth"}}
waiting := make(chan bool)
for _, element := range elements {
go func(element *Element){
fmt.Println("Element Name: ", element.Name)
waiting <- true
}(&element)
}
for i := 0; i < 4; i++{
<- waiting
}
}
I expected the code to write:
- 'first'
- 'second'
- 'third'
- 'fourth'
in any order but instead it is printing:
- 'fourth'
- 'fourth'
- 'fourth'
- 'fourth'
So it seems as the anonymous go function 'resolves' it's *Element parameter to whatever was in that loop at that time, so this code would be fixed by passing the Element{} itself instead of the pointer to the element.
My question is:
- Is this defined behaviour?
- How could i rewrite this to accept
pointers to my Element{}?
Playground:
http://play.golang.org/p/tcRvforQE4
Edit: question formatting
答案1
得分: 8
以下是翻译好的内容:
发生的情况是,for循环在每次迭代中将elements[i]
的值放入同一个element
变量中,而不是创建一个新的变量。这意味着&element
始终是相同的地址(在调用函数之前尝试打印它!)
一个简单的解决方案是将指向切片实际成员的指针传递给它:
for i := range elements {
go func(element *Element){
fmt.Println("PostStream: ", element.Name)
waiting <- true
}(&elements[i])
}
英文:
What happens is that the for loop places the value of elements[i]
in the same element
variable for each iteration, not creating a new one. This means that &element
is always the same address (try printing it before calling the function!)
A simple solution would be to just pass it a pointer to the actual memeber of the slice:
for i := range elements {
go func(element *Element){
fmt.Println("PostStream: ", element.Name)
waiting <- true
}(&elements[i])
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论