0
0

More than 3 years have passed since last update.

Goのloopclosureについて

Posted at

ある日、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
0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0