Golang延迟行为

rem*_*ada 50 go

有效的Go 表示以下有关延期:

延迟函数的参数(如果函数是方法,包括接收器)在延迟执行时计算,而不是在调用执行时计算.除了避免担心变量在函数执行时更改值,这意味着单个延迟调用站点可以推迟多个函数执行.这是一个愚蠢的例子.

for i := 0; i < 5; i++ {
    defer fmt.Printf("%d ", i)
}
Run Code Online (Sandbox Code Playgroud)

延迟函数以LIFO顺序执行,因此该4 3 2 1 0函数返回时将打印此代码.

这个例子让我很困惑.如果在执行延迟调用时评估参数,那么for循环中5 5 5 5 5的延迟应该打印,因为当for循环结束时将调用defer ,并且此时i将为5. 在for循环结束时评估延迟将因此导致所有呼叫都为5.

我在这里错过了什么吗?

Von*_*onC 45

这似乎是连贯的(另见" 延迟,恐慌和恢复 ")

在周围函数返回,延迟函数调用以Last In First Out顺序执行.

此功能打印"3210":

func b() {
    for i := 0; i < 4; i++ {
        defer fmt.Print(i)
    }
}
Run Code Online (Sandbox Code Playgroud)

defer评估时的最后一次调用意味着i=3,前一个到最后一个意味着i=2等等.

Golang规范:

每次defer执行" "语句时,将像往常一样评估调用的函数值和参数,并重新保存,但不执行实际的函数体.


defers将被调用时,FUNC结束

是的,但是他们的参数在循环运行之前进行了评估.

当你使用闭包(函数文字)时,你在" 如何golang"推迟"捕获闭包的参数? "中有一个更棘手的延迟案例,详见" Golang中封闭体后的 " 为什么添加" ".()

  • 是的,按照规范:“每次执行“ defer”语句时,将照常评估调用的函数值和参数,并重新保存,但不执行实际的函数主体。” 而且,您不是唯一对此感到困惑/惊讶的人。:) (2认同)

two*_*two 14

更进一步,规范还明确表示在defer语句运行时评估参数,而不是在实际调用延迟函数的返回/恐慌时间:

每次执行"延迟"语句时,将像往常一样评估调用的函数值和参数,并重新保存,但不执行实际的函数体.

是的,一次评估参数并且函数体在另一个上运行肯定会令人困惑.我被它抓住了.


joc*_*hen 5

我认为您对“延迟执行”和“执行呼叫”这两个短语的含义感到困惑。我相信,“延迟执行”是指控制流到达以开头的行defer在循环内发生了五次。相反,“调用执行” fmt.Printf("%d ", i)是执行时,周围的函数返回时。

如果此解释正确,则您的语句“因为将在for循环结束时调用defers”是错误的(printf将在循环之后调用,但defer在内部调用),并且所有内容均与其他答案中解释的行为一致。