在循环中使用匿名Go函数传递指针只会使用最后一个元素的指针。

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

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 &quot;fmt&quot;

type (
	Element struct{
		Name string
	}
)

func main() {
	elements := []Element{{&quot;first&quot;}, {&quot;second&quot;}, {&quot;third&quot;}, {&quot;fourth&quot;}}
	waiting := make(chan bool)

	for _, element := range elements {
		go func(element *Element){
			fmt.Println(&quot;Element Name: &quot;, element.Name)
			waiting &lt;- true
		}(&amp;element)
	}
	
	for i := 0; i &lt; 4; i++{
		&lt;- 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变量中,而不是创建一个新的变量。这意味着&amp;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 &amp;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(&quot;PostStream: &quot;, element.Name)
        waiting &lt;- true
    }(&amp;elements[i])
}

huangapple
  • 本文由 发表于 2014年5月14日 00:44:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/23637099.html
匿名

发表评论

匿名网友

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

确定