延迟函数调用和闭包捕获
在 Go 中,defer 语句允许我们在周围函数返回之前执行函数。 defer 的一个重要方面是它如何处理闭包。
在此代码片段中:
package main import "fmt" func main() { var whatever [5]struct{} for i := range whatever { fmt.Println(i) } // part 1 for i := range whatever { defer func() { fmt.Println(i) }() // part 2 } for i := range whatever { defer func(n int) { fmt.Println(n) }(i) // part 3 } }
第 1 部分只是打印从 0 到 4 的 i 值。然而,第 2 部分演示了一个有趣的行为。它没有打印 0 到 4 的预期值,而是输出“44444”。
这是因为第 2 部分中的闭包捕获了 i 变量。当稍后执行闭包时, i 变量的值是在 range 语句的最后一次迭代中的值,即 4。因此,所有延迟函数都调用 print 4。
相比之下,部分3 不捕获任何外部变量。根据 Go 规范,“每次执行‘defer’语句时,调用的函数值和参数都会照常评估并重新保存,但不会调用实际函数。”这意味着每个延迟函数调用都有不同的“n”参数值,即执行“defer”语句时“i”的值。
因此,第 3 部分正确打印“43210”,因为延迟函数调用在周围函数返回之前按 LIFO 顺序(后进先出)执行。
它是重要的是要记住,“defer f()”中的函数表达式不会在 defer 语句执行时执行,而“defer f(e)”中的表达式会立即计算。
以上是为什么 `defer func() { fmt.Println(i) }()` 在 Go 中打印'44444”,而 `defer func(n int) { fmt.Println(n) }(i)` 正确打印'43210” ?的详细内容。更多信息请关注PHP中文网其他相关文章!