ある日、vim-go が loopclosure というワーニングを吐いた。
for文の中で関数を定義して、そのループ内で作った関数を呼ばない場合は、その時のanswerを渡してくれるわけではないみたい。
下のコードは a, bと表示して欲しいのだが、b, bと表示されてしまう。
package main
import (
"fmt"
)
func main() {
answers := []string{"a", "b"}
var funcs []func()
for _, answer := range answers {
funcs = append(funcs, func() {
fmt.Println(answer)
})
}
for _, f := range funcs {
f()
}
}
# =>
b
b
正しくはこう
package main
import (
"fmt"
)
func main() {
answers := []string{"a", "b"}
var funcs []func()
for _, answer := range answers {
++ answer := answer
funcs = append(funcs, func() {
fmt.Println(answer)
})
}
for _, f := range funcs {
f()
}
}
# =>
a
b
並行処理したいときも要注意です。
下のコードだと、b, b が表示されちゃいます。(次のループに行く前にprintされたら別だけど)
package main
import (
"fmt"
"time"
)
func main() {
answers := []string{"a", "b"}
for _, answer := range answers {
go func() {
fmt.Println(answer)
}()
}
time.Sleep(time.Second)
}
# =>
b
b