Go-延迟函数的不一致求值



我正在尝试Go,并看到一些延迟函数的意外行为。考虑以下程序,该程序将全局变量递增给定的量。

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
    println("z =", z, "Inside Increase Function")
    return z
}

当在操场上跑步时,输出:

z = 21 Inside Increase Function
z = 51 Inside Increase Function
z = 61 Inside Increase Function
z = 51 Main Value
z = 51 Deferred Value 2
z = 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 Function
z = 51 Inside Increase Function
z = 51 Main Value
z = 61 Inside Increase Function
z = 51 Deferred Value 2
z = 21 Deferred Value 1

Go文档说明:

延迟调用的参数会立即求值,但直到周围的函数返回,才执行函数调用。

因此,被评估的参数可以解释为什么返回的Main Value是51而不是61,因为fmt。Println语句将increaseZ作为参数,但直到主函数返回后才会调用defer increaseZ(10)

然而,这并不能解释为什么在第一示例中increaseZ(10)在main完成之前输出,而在第二示例中在main完成之后输出。

如果有人能帮助我了解这里发生了什么,我将不胜感激,因为这看起来像是未来难以诊断的bug的沃土。

您的打印目的地不一致。

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

这与延迟评估无关。这是关于印刷的。println函数是为了完整性而记录的,但不能保证完全保留在该语言中。此外,Stdout和Stderr通过设计在操场上合并为一个流。如果在任何地方都使用fmt.Println(...)http://play.golang.org/p/PU3hxHCazA或明确定义fmt.Fprintln(os.Stdout, ...http://play.golang.org/p/OQpOQR2vm0事情会按预期进行的。

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

最新更新