首页  >  文章  >  后端开发  >  为什么在 Go 中延迟关闭捕获会导致意外行为?

为什么在 Go 中延迟关闭捕获会导致意外行为?

Linda Hamilton
Linda Hamilton原创
2024-11-10 19:35:02455浏览

Why Does Deferring Closure Capture in Go Lead to Unexpected Behavior?

Go 中延迟闭包捕获

Go 的 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
}

代码的输出是:

0
1
2
3
4
4
3
2
1
0
4
4
4
4
4

分析

  • 第 1 部分: 按预期打印循环计数器 i。
  • 第 2 部分: 捕获闭包中的变量 i。但是,当闭包执行时, i 具有循环最后一次迭代的值,即 4。因此,它打印“44444”。
  • 第 3 部分: 不捕获任何外部变量。执行 defer 语句时会评估闭包,因此每个 defer 调用都有不同的 n 值,结果为“43210”。

主要区别

第 2 部分和第 3 部分之间的关​​键区别在于闭包是否捕获外部变量。在第 2 部分中,闭包捕获 i,它是对外部变量的引用。在第 3 部分中,闭包没有任何外部引用,因此每个调用都有不同的 n 值。

其他注意事项

  • 延迟调用是在周围函数返回之前按后进先出 (LIFO) 顺序执行。
  • defer 语句时计算的表达式执行,而不是函数本身。

以上是为什么在 Go 中延迟关闭捕获会导致意外行为?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn