首页 >后端开发 >Golang >为什么 `defer func() { fmt.Println(i) }()` 在 Go 中打印'44444”,而 `defer func(n int) { fmt.Println(n) }(i)` 正确打印'43210” ?

为什么 `defer func() { fmt.Println(i) }()` 在 Go 中打印'44444”,而 `defer func(n int) { fmt.Println(n) }(i)` 正确打印'43210” ?

DDD
DDD原创
2024-11-10 18:54:02499浏览

Why does `defer func() { fmt.Println(i) }()` print

延迟函数调用和闭包捕获

在 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中文网其他相关文章!

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