Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Closures in go routines have incorrect scope unless the variables are copied

Tags:

go

I am seeing incorrect values in the functions run as goroutines. They don't seem to be capturing the values from the scope in which they were invoked unless copied into new variables.

http://play.golang.org/p/YZYi-IVuYm

vs.

http://play.golang.org/p/z88G99XSi6

like image 677
flying monkey Avatar asked Jun 13 '14 00:06

flying monkey


3 Answers

You either need to re-assign the variable in the local context so that the closure can capture the values:

http://play.golang.org/p/-NO4S4qCZf

package main

import "fmt"
import "time"

func main() {
    l := []int{1, 2, 3}
    for idx, item := range l {
        theIdx, theItem := idx, item
        go func() {
            fmt.Println(theIdx, theItem)
        }()
    }
    time.Sleep(time.Second)
}

or you pass the values to the goroutine and add parameters to the function

http://play.golang.org/p/5gNToDWSQR

package main

import "fmt"
import "time"

func main() {
    l := []int{1, 2, 3}
    for idx, item := range l {
        go func(idx, item int) {
            fmt.Println(idx, item)
        }(idx, item)
    }
    time.Sleep(time.Second)
}
like image 138
fabrizioM Avatar answered Oct 16 '22 11:10

fabrizioM


This is expected, and documented in the Go "Common Mistakes" page. You can argue with the design decision, but it is a known effect.

A recommended way to do this is to pass the values in as parameters.

like image 35
Gian Avatar answered Oct 16 '22 10:10

Gian


By the time the first goroutine is executed, idx and item have already been overwritten with the next values. As the routines are executed within the same scope, you get the new values.

It does make sense, in hindsight.

like image 2
Ferdy Avatar answered Oct 16 '22 09:10

Ferdy