Go のさまざまなループの動作を理解する
Go でループを構築する場合、for range ループの動作を理解することが重要です。異なる動作を示す次の 2 つのループ バリエーションを考えてみましょう:
ループ バリエーション 1:
func loop1() { actions := make(map[string]func()) for _, cmd := range cmds { actions[cmd] = func() { fmt.Println(cmd) } } for _, action := range actions { action() } }
ループ バリエーション 2:
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:
問題は funcloop1() ループにあります。各ループ反復では、関数リテラルがアクション マップに割り当てられます。この関数リテラルはループ変数 cmd を参照します。ただし、cmd のインスタンスは 1 つだけであり、ループが終了すると、コマンド スライスの最後の値である「update」が保持されます。これは、囲まれたすべての関数が同じループ変数 (cmd) を参照することを意味し、その結果、呼び出されたときにすべての関数が「update」を出力します。
解決策:
これを修正するには、各ループ反復内でループ変数のコピーを作成するため、各関数リテラルは独自の独立したリテラルを持ちます。 copy:
func loop1() { actions := make(map[string]func()) for _, cmd := range cmds { cmd2 := cmd actions[cmd] = func() { fmt.Println(cmd2) // Refer to the detached, copy variable! } } for _, action := range actions { action() } }
結論:
結論として、for range ループを使用する場合は、ループ変数のスコープと参照を考慮することが重要です。必要なときにループ変数のコピーが作成されるようにすることで、特にそれらの変数を参照する関数リテラルを扱う場合に、正しい動作が保証されます。
以上がGo の「for range」ループが関数リテラルで異なる動作を示すのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。