为了账号安全,请及时绑定邮箱和手机立即绑定

Go - 延迟函数的不一致评估

Go - 延迟函数的不一致评估

Go
慕村225694 2021-09-27 14:19:16
我正在尝试使用 Go 并且看到一些带有延迟函数的意外行为。考虑以下将全局变量增加给定数量的程序。package mainimport "fmt"var z = 1func main() {    defer increaseZ(10)    defer fmt.Println("z =", increaseZ(20), "Deferred Value 1")    defer fmt.Println("z =", increaseZ(30), "Deferred Value 2")    fmt.Println("z =", z, "Main Value")}func increaseZ(y int) int {    z += y    println("z =", z, "Inside Increase Function")    return z}当在 go playground 中运行时,输出:z = 21 Inside Increase Functionz = 51 Inside Increase Functionz = 61 Inside Increase Functionz = 51 Main Valuez = 51 Deferred Value 2z = 21 Deferred Value 1如果我切换延迟函数的顺序,它还有另一个效果:defer fmt.Println("z =", increaseZ(20), "Deferred Value 1")defer fmt.Println("z =", increaseZ(30), "Deferred Value 2")defer increaseZ(10)输出:z = 21 Inside Increase Functionz = 51 Inside Increase Functionz = 51 Main Valuez = 61 Inside Increase Functionz = 51 Deferred Value 2z = 21 Deferred Value 1Go 文档指出:延迟调用的参数会立即计算,但直到周围的函数返回时才会执行函数调用。因此,正在评估的参数可以解释为什么返回的 Main Value 是 51 而不是 61,因为 fmt.Println 语句将increaseZ作为参数,但defer increaseZ(10)在 main 函数返回之前不会被调用。但是,这并不能解释为什么在第一个示例中increaseZ(10)在 main 完成之前输出,而在第二个示例中在 main 完成之后输出。如果有人能帮助我了解这里发生的事情,我将不胜感激,因为这看起来像是难以诊断错误的沃土。
查看完整描述

3 回答

?
BIG阳

TA贡献1859条经验 获得超6个赞

您的打印目的地不一致。


stdout: fmt.Println


stderr: println

写入相同的打印目的地。


package main


import "fmt"


var z = 1


func main() {


    defer increaseZ(10)

    defer fmt.Println("z =", increaseZ(20), "Deferred Value 1")

    defer fmt.Println("z =", increaseZ(30), "Deferred Value 2")


    fmt.Println("z =", z, "Main Value")

}


func increaseZ(y int) int {

    z += y

    fmt.Println("z =", z, "Inside Increase Function")

    return z

}

输出:


z = 21 Inside Increase Function

z = 51 Inside Increase Function

z = 51 Main Value

z = 51 Deferred Value 2

z = 21 Deferred Value 1

z = 61 Inside Increase Function

或者,


package main


import (

    "fmt"

    "os"

)


var z = 1


func main() {


    defer increaseZ(10)

    defer fmt.Fprintln(os.Stderr, "z =", increaseZ(20), "Deferred Value 1")

    defer fmt.Fprintln(os.Stderr, "z =", increaseZ(30), "Deferred Value 2")


    fmt.Fprintln(os.Stderr, "z =", z, "Main Value")

}


func increaseZ(y int) int {

    z += y

    println("z =", z, "Inside Increase Function")

    return z

}

输出:


z = 21 Inside Increase Function

z = 51 Inside Increase Function

z = 51 Main Value

z = 51 Deferred Value 2

z = 21 Deferred Value 1

z = 61 Inside Increase Function


查看完整回答
反对 回复 2021-09-27
?
红糖糍粑

TA贡献1815条经验 获得超6个赞

我怀疑这是 Go 游乐场的错误。当我在我的机器上编译并运行这个程序时,它会产生预期的输出。一个bug报告关于这个问题已经提交。


查看完整回答
反对 回复 2021-09-27
  • 3 回答
  • 0 关注
  • 237 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信