Go の For ループの動作を理解する
プログラミングでは、特定の構造が予期しない動作を引き起こす可能性があります。 for ループの次の 2 つのバリエーションを考えてみましょう。
var cmds = []string{"create", "delete", "update"} func loop1() { actions := make(map[string]func()) for _, cmd := range cmds { actions[cmd] = func() { fmt.Println(cmd) } } for _, action := range actions { action() } } func loop2() { actions := make(map[string]func()) for i, cmd := range cmds { command := cmds[i] actions[cmd] = func() { fmt.Println(command) } } for _, action := range actions { action() } }
ループ 1 は「update」を 3 回出力し、loop2 は「delete」、「update」、および「create」を出力します。この動作を理解するために、詳細を調べてみましょう。
ループ変数の参照
loop1 では、ループ変数 cmd を宣言し、それを使用して cmds スライスを反復処理します。 。ただし、ネストされたループ内では、変数 cmd は引き続き外側のループからループ変数を参照します。
クロージャでの値の共有
マップ内に関数リテラルを作成するときアクションでは、ループ変数 cmd がクロージャによってキャプチャされます。これは、各関数がコピーではなく、同じループ変数インスタンスへの参照を継承することを意味します。
最終値の依存関係
ネストされたループが完了するまでに、ループ変数 cmd はスライス内の最後の要素 (「更新」) まで進みました。これは、すべてのクロージャが最後の要素を参照することを意味します。
結果:
ネストされたループ内で印刷する場合、すべてのクロージャは「update」を印刷します。これは、すべてのクロージャが最後の要素を参照しているためです。の同じ最後の要素この問題を解決するには、cmd2 := cmd を使用して、loop1 にループ変数のコピーを作成し、そのコピーを関数リテラルで使用します。 。これにより、各クロージャが作成時に cmd の値への個別の参照を持つことが保証されます。
この明確化により、クロージャ内でループ変数を参照する際の微妙な違いが強調され、クロージャが Go でどのように変数をキャプチャするかを注意深く理解することの重要性が示されています。 .
以上がこの Go コード例で、ループ 2 が異なる値を出力するのに、ループ 1 は「update」を 3 回出力するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。