goroutineで実行されるクロージャー(closure)で予期せぬ値が出力される

0

2022年04月08日 13:15

goroutineで実行されるクロージャーをループ内で起動した際に予期せぬ値が出力されることがあります。
例えば下記のようなvaluesをループで展開、その中でgoroutineを起動して値を出力してみます。

img
出力
img
Go Playgroundからも確認できます

なぜスライスの最後の要素だけ出力されるか

原因は以下2つの理由です。

  • goroutineは起動に時間がかかる
  • for分のvは同じインスタンスを参照する変数

原因を1つ1つみていきます。

goroutineは起動に時間がかかる

goroutineは起動に時間がかかります。上記コードにもtime.Sleep(time.Second)があるのもgoroutineが起動する前にmain関数が終了するのを防ぐためです。

for分のvは同じインスタンスを参照する変数

またfor分のvは同じ変数を参照しています。なのでgoroutineが起動する時には、ループが回り切っておりvにはスライスの最後の要素erikoが格納されています。

goroutineが起動する時にはvにスライスの最後の要素が入っている

上記2つを合わせるとgoroutineが起動する時には変数vにはスライスの最後の要素erikoが入っており、クロージャー内のvではその値が参照されます。

どうやって防ぐか

2つの方法があります。

  • クロージャーの引数にvを渡す
  • 新しく変数を定義する

クロージャーの引数にvを渡す

クロージャーの引数にvを渡すことで順番通りに変数にアクセスすることができます。
img
出力
img

新しく変数を定義する

変数の値をコピーして、新たな変数を作成することでクロージャーでも順番通りアクセスすることができます。
img
出力
img

参考

https://go.dev/doc/faq#closures_and_goroutines

# Go
0

診断を受けるとあなたの現在の業務委託単価を算出します。今後副業やフリーランスで単価を交渉する際の参考になります。また次の単価レンジに到達するためのヒントも確認できます。

目次を見る