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

Go-延迟函数的不一致求值,go,deferred-execution,Go,Deferred Execution,我正在试验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")

我正在试验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文档说明:

将立即计算延迟调用的参数,但 函数调用在周围函数返回之前不会执行

因此,正在求值的参数可能会解释为什么返回的主值是51而不是61,因为fmt.Println语句将
increaseZ
作为参数,但是
defer increaseZ(10)
直到主函数返回后才会被调用

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


如果有人能帮助我了解这里发生了什么,我将不胜感激,因为这里似乎是难以诊断的细菌的沃土。

我怀疑这是Go游乐场的细菌。当我在我的机器上编译并运行这个程序时,它会产生预期的输出。这个问题的相关文件已经提交。

我怀疑这是Go游乐场的一个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
}
写入相同的打印目标

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
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
或者

输出:

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
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

您的打印目标不一致

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
}
写入相同的打印目标

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
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
或者

输出:

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
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(…)

或者明确定义
fmt.Fprintln(os.Stdout,
事情会按预期进行。

这不是关于延迟的评估。这是关于打印。
println
函数记录完整,但不保证保留在语言中。此外,Stdout和Stderr通过设计在操场上合并为一个流。 如果您在任何地方都使用
fmt.Println(…)

或者显式定义
fmt.Fprintln(os.Stdout,
事情会按预期进行。

这很有趣。游乐场不会交错Stdout和stderr。请参阅。将
println
更改为
fmt.println
以获得预期的输出。不要以特定于实现的方式使用“[…]这很有趣。游乐场不会交错使用stdout和stderr。请参阅。将
println
更改为
fmt.println
,以获得预期的输出。不要以特定于实现的方式使用“[…]它不一定会保留在该语言中。”经过验证,在
go1.4.2 darwin/amd64上编译时,它按预期运行。注意:已被拒绝为无效。没有Go错误。行为如预期。错误在程序中。有关详细信息,请参阅我的答案。它未被拒绝,我关闭了它。奇怪的是,我无法通过任何其他方式重现此行为。Vali日期为,在
go1.4.2 darwin/amd64上编译时,它按预期运行。注意:已被拒绝为无效。没有Go错误。行为如预期。错误在程序中。有关详细信息,请参阅我的答案。它未被拒绝,我关闭了它。奇怪的是,我无法通过任何其他方式重现此行为。
println
writing to
stderr
完美地解释了这一点。你能分享一下这一点吗?@PassKit:在Go伪包文档中。
println
内置函数以特定于实现的方式格式化其参数,并将结果写入标准错误。
println
writing to
stderr
解释得很好。你能分享一下这是在哪里记录的吗?@PassKit:在Go伪包文档中:
println
内置函数以特定于实现的方式格式化其参数,并将结果写入标准错误。