当前位置: 首页 > 面试题库 >

golang的“延迟”如何捕获闭包的参数?

沃阳飙
2023-03-14
问题内容

这是我的代码(运行):

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

问题:第2部分和第3部分有什么区别?为什么第2部分输出“ 44444”而不是“ 43210”?


问题答案:

“第2部分”闭包捕获变量“ i”。当闭包(稍后)中的代码执行时,变量“ i”具有在range语句的最后一次迭代中具有的值,即。‘4’。因此

4 4 4 4 4

输出的一部分。

“第3部分”在其闭包中未捕获任何外部变量。如规格所述:

每次执行“ defer”语句时,将照常评估调用的函数值和参数并重新保存,但不会调用实际函数。

因此,每个延迟的函数调用都具有不同的’n’参数值。它是执行defer语句时的’i’变量的值。因此

4 3 2 1 0

部分输出,因为:

…延迟调用将在周围函数返回之前立即按LIFO顺序执行…

需要注意的关键点是,在 执行 defer语句时,不会 执行 “ defer f()”中的“ f()”

当执行defer语句时,将 评估 “ defer f(e)”中的表达式“ e” 。



 类似资料:
  • 闭包本身是相当灵活的,可以实现所需功能来让闭包运行而不用类型标注(原文:Closures are inherently flexible and will do what the functionality requires to make the closure work without annotation)。这允许变量捕获灵活地适应使用 情况,有时是移动(moving)有时是借用(borro

  • 问题内容: 测试代码如下: 我认为输出将是:java,python,erlang,cpp,go;但是输出是:go go go go go; 怎么了 问题答案: 就是这样写函数,把动词变成函数

  • 问题内容: 关于延期,Effective Go 声明以下内容: 延迟函数(如果函数是方法,则包括接收方)的参数在 延迟 执行时而不是在 调用 执行时进行评估。除了避免担心函数执行时变量会更改值外,这还意味着单个延迟的调用站点可以延迟多个函数的执行。这是一个愚蠢的例子。 延迟函数以LIFO顺序执行,因此该函数返回时将导致打印此代码。 这个例子使我感到困惑。如果在执行defer调用时评估了参数,则应该

  • 问题内容: 更改了该方法的结构后,当defer调用两次时会发生什么? 例如: 其中当最后叫什么名字? 问题答案: 它取决于方法的接收者 和 变量的类型。 简短的答案:如果您使用的是包,则延迟的方法将正确关闭两个实例,因为它们具有 指针 接收器, 并且 由于返回了 指针 ( 指针 也是如此)。请参阅下面的推理和解释。 为避免混淆,我建议使用不同的变量,这样会清楚您 想要 什么以及 将要 关闭的内容:

  • Go 语言中没有提供其它面向对象语言的析构函数,但是 Go 语言提供了 defer 语句用于实现其它面向对象语言析构函数的功能 defer 语句常用于 释放资源、解除锁定 以及 错误处理 等 例如C语言中我们申请了一块内存空间,那么不使用时我们就必须释放这块存储空间 例如C语言中我们打开了一个文件,那么我们不使用时就要关闭这个文件 例如C语言中我们打开了一个数据库, 那么我们不使用时就要关闭这个数

  • 问题内容: 我正在使用Firebase观察事件,然后在完成处理程序中设置图像 但是我收到此错误 闭包不能隐式捕获变异的自身参数 我不确定这个错误是什么,寻找解决方案并没有帮助 问题答案: 短版 拥有您的调用的类型很可能是值类型(a ?),在这种情况下,变异上下文可能不会在闭包中显式捕获。 一种简单的解决方案是将您的拥有类型更新为一次引用()。 较长的版本 Firebase的方法声明如下 所述封闭件