Passing a pointer inside a loop with anonymous go functions causes only last element pointer to be used

Issue

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

Solution

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

Answered By – Not_a_Golfer

Answer Checked By – Terry (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.