Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 214
Rohan Avatar asked Feb 14 '23 00:02

Rohan


1 Answers

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])
}
like image 102
Not_a_Golfer Avatar answered May 01 '23 06:05

Not_a_Golfer