Understanding Different Loop Behavior in Go
When constructing loops in Go, it's crucial to understand the behavior of the for range loop. Consider the following two loop variations that exhibit distinct behavior:
Loop Variation 1:
func loop1() { actions := make(map[string]func()) for _, cmd := range cmds { actions[cmd] = func() { fmt.Println(cmd) } } for _, action := range actions { action() } }
Loop Variation 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() } }
Output Observations:
Underlying Issue in Loop Variation 1:
The problem lies in the func loop1() loop. Each loop iteration assigns a function literal to the actions map. This function literal references the loop variable cmd. However, there is only one instance of cmd, and when the loop finishes, it holds the last value in the commands slice, which is "update." This means that all enclosed functions reference the same loop variable (cmd), which results in all functions printing "update" when called.
Solution:
To rectify this, make a copy of the loop variable within each loop iteration, so each function literal has its own independent 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() } }
Conclusion:
In conclusion, when using the for range loop, it's critical to consider the scope and references of loop variables. Ensuring that copies of loop variables are made when necessary ensures correct behavior, particularly when dealing with function literals that reference those variables.
The above is the detailed content of Why Does Go's `for range` Loop Exhibit Different Behavior with Function Literals?. For more information, please follow other related articles on the PHP Chinese website!