理解 Go 中的 For 循环行为
在编程中,某些构造可能会导致意外的行为。考虑 for 循环的这两种变体:
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() } }
Loop1 打印“update”三次,而 Loop2 打印“delete”、“update”和“create”。为了理解这种行为,让我们深入研究细节。
循环变量参考
在loop1中,我们声明一个循环变量cmd并使用它来迭代cmds切片。然而,在嵌套循环中,变量 cmd 仍然引用外层循环中的循环变量。
闭包中的值共享
在映射中创建函数文字时actions 中,循环变量 cmd 被闭包捕获。这意味着每个函数继承对同一循环变量实例的引用,而不是副本。
Last Value Dependency
当嵌套循环完成时,循环变量 cmd 已前进到切片中的最后一个元素(“更新”)。这意味着所有闭包现在都引用最后一个元素。
结果:
在嵌套循环内打印时,所有闭包都会打印“update”,因为它们都引用中的最后一个元素相同
修复:
要解决此问题,我们使用 cmd2 := cmd 在 Loop1 中创建循环变量的副本,并在函数文字中使用该副本。这确保每个闭包在创建时都对 cmd 的值有一个不同的引用。
这一澄清强调了在闭包中引用循环变量的细微差别,并演示了仔细理解闭包如何在 Go 中捕获变量的重要性.
以上是在这个 Go 代码示例中,为什么 Loop1 打印'更新”三次,而 Loop2 打印不同的值?的详细内容。更多信息请关注PHP中文网其他相关文章!