関数のスライスをループし、その中のすべての関数を呼び出しようとしています。しかし、私は奇妙な結果を得ています。私のコードは次のとおりです:各関数を繰り返し関数スライスで呼び出す
私はそれが関数A、B、そしてCを呼び出すと思っていましたが、私の出力はCしか得られません。
何が間違っているのか、その背後にある論理を示唆してください。また、どのように私は希望の動作を得ることができます。
関数のスライスをループし、その中のすべての関数を呼び出しようとしています。しかし、私は奇妙な結果を得ています。私のコードは次のとおりです:各関数を繰り返し関数スライスで呼び出す
私はそれが関数A、B、そしてCを呼び出すと思っていましたが、私の出力はCしか得られません。
何が間違っているのか、その背後にある論理を示唆してください。また、どのように私は希望の動作を得ることができます。
クラシック行く落とし穴:)
公式ゴーFAQ
for a, _ := range f {
wg.Add(1)
a:=a // this will make it work
go func() {
defer wg.Done()
f[a]()
}()
}
あなたfunc() {}()
はa
の上に閉じ閉鎖です。 a
は、すべてのgo func
goルーチンで共有されます。forループは同じvar(同じ値をメモリ内に意味し、同じ値を意味する)を再利用するため、当然彼らはすべて最後の値a
を参照します。
解決策は、上記のように閉じる前にa:=a
を再宣言してください。これにより、新しいvar(メモリ内の新しいアドレス)が作成され、それはgo func
の呼び出しごとに新しいものになります。
それとも、その場合には、あなたがそうのようa
の値のコピーを渡し、外出先での関数のパラメータとして渡す:
go func(i int) {
defer wg.Done()
f[i]()
}(a)
あなたも、このhttps://play.golang.org/p/nkP9YfeOWF例えば、外出先ルーチンを持っている必要はありません。同じようなことを示しています。ここの鍵は「閉鎖」です。
問題は、goroutineに希望の値を渡していないことが原因で、変数値が外側スコープから取得されているようです。つまり、最初のgoroutineが実行される前でも範囲の反復処理が完了しているため、常にインデックスa == 2を取得しています。つまり、関数Cです。 time.Sleep(100)をinsideあなたの範囲、ちょうどゴルーチンは、次の繰り返しに進む前に、メインスレッドに追いつくことを可能にする - >GO playground
for a, _ := range f {
wg.Add(1)
go func() {
defer wg.Done()
f[a]()
}()
time.Sleep(100)
}
出力
A
B
C
何がやりたいことは、単に合格ですが、関数のコピーを作るゴルーチンへのパラメータ。
func main() {
type fs func()
var wg sync.WaitGroup
f := []fs{A, B, C}
for _, v := range f {
wg.Add(1)
go func(f fs) {
defer wg.Done()
f()
}(v)
}
wg.Wait()
}