3

I am trying to build an array of functions that contain an enclosed variable (in this case a string) but I was getting some unexpected output. I figure the reason I am getting this output is because the func literal being appended is actually a pointer to code that is being changed after each iteration.

Is there a way to new() or make() a function type so that append() will get a different function instance per iteration instead?

package main

import "log"

var functions []func()

func main() {
    for _, s := range [...]string{"goodbye", "cruel", "world"} {
        functions = append(functions, func() {
            log.Println(s)
        })
    }
    for _, f := range functions {
        f()
    }
}

Outputs:

2014/11/23 18:13:16 world
2014/11/23 18:13:16 world
2014/11/23 18:13:16 world
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
BlinkyTop
  • 1,124
  • 3
  • 14
  • 19

1 Answers1

3

Each iteration of the loop uses the same instance of the variable s, so each closure shares that single variable. To bind the current value of s to each closure as it is launched, one must modify the inner loop to create a new variable each iteration. For example,

package main

import "log"

var functions []func()

func main() {
    for _, s := range [...]string{"goodbye", "cruel", "world"} {
        s := s // create new s
        functions = append(functions, func() {
            log.Println(s)
        })
    }
    for _, f := range functions {
        f()
    }
}

Output:

2009/11/10 23:00:00 goodbye
2009/11/10 23:00:00 cruel
2009/11/10 23:00:00 world

References:

What happens with closures running as goroutines?

Captured Closure (for Loop Variable) in Go

Community
  • 1
  • 1
peterSO
  • 158,998
  • 31
  • 281
  • 276