Go でキャプチャされたクロージャ: 範囲ループ変数の動作を理解する
Go では、for...range ループは他の for- ループとは異なる動作をします。ループはクロージャとして扱われるためです。この記事では、クロージャ変数内でレンジ ループ変数をキャプチャする微妙な違いについて説明します。
レンジ ループでキャプチャされたクロージャ動作
C# の foreach ループとは異なり、Go の for...rangeループはループ変数 (キーや値など) をクロージャ変数としてキャプチャします。ただし、Go はこれらの変数をループ スコープから直接キャプチャしません。代わりに、ループのクロージャ内で最後に割り当てられた値としてそれらをキャプチャします。
この動作は、サンプル コードで示されているように、Go でクロージャを使用してタプルを作成しようとすると明らかになります。クロージャは、for...range ループ中に k 変数と v 変数に割り当てられた最後の値をキャプチャするため、誤った動作が発生します。
修正: キャプチャ用の変数のコピー
この問題に対処するには、ループ変数を := 演算子を使用してローカル変数に明示的にコピーしてから、ループ変数をキャプチャする必要があります。クロージャ.
for k, v := range m { kLocal, vLocal := k, v // Copy values to local variables f[i] = func() { return kLocal, vLocal } }
k と v を kLocal と vLocal にコピーすることで、クロージャは for...range の反復中にループ変数の意図した値に正しくアクセスできるようになります。
クロージャと関数リテラル
Go におけるクロージャと関数リテラルの違いに注意することが重要です。関数リテラルは現在のスコープにバインドされた新しい関数を作成しますが、クロージャーはそれを囲んでいるスコープと共有変数へのアクセスを保持します。
値ループと変数ループ
さらに、 Go は値ループと変数ループを区別します。値ループはループ変数のコピーを各クロージャにバインドし、変数ループは実際のループ変数をバインドします。それ自体。コード例で見られるように、これにより異なる動作が発生する可能性があります。
結論として、Go でクロージャ内の範囲ループ変数をキャプチャするには、クロージャのスコープと、必要な値をコピーするためのローカル変数の使用に注意する必要があります。これらの概念を理解することは、効果的で堅牢な Go コードを作成するために不可欠です。
以上がGo の「for...range」ループはクロージャ変数をどのように処理しますか?また、予期しない動作を回避するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。