我正在试验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
}
当run in the go playground时,输出:
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
作为参数,但是{{1}直到main函数返回后才会被调用。
但是,这并不能解释为什么在第一个例子中defer increaseZ(10)
在main完成之前输出,并且在main完成之后在第二个例子中输出。
如果有人能帮助我理解这里发生的事情,我将不胜感激,因为这看起来很难诊断出难以诊断的错误。
答案 0 :(得分:2)
您的打印目的地不一致。
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
答案 1 :(得分:2)
不是延期评估。这是关于印刷的。记录println
函数的完整性,但不保证完全保留在语言中。此外,Stdout和Stderr通过设计在Playground的一个流中合并。
如果您在fmt.Println(...)
处使用fmt.Fprintln(os.Stdout, ...
或者明确定义{{1}} http://play.golang.org/p/PU3hxHCazA事物将按预期工作。
答案 2 :(得分:0)
我怀疑这是Go游乐场的一个错误。当我在我的机器上编译并运行该程序时,它会产生预期的输出。有关此问题的bug report已提交。