douzi2749 2015-03-28 12:08
浏览 12
已采纳

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

I am experimenting with Go and am seeing some unexpected behaviour with deferred functions. Consider the following program that increments a global variable by a given amount.

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
}

When run in the go playground, this outputs:

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

If I switch the order of the deferred functions, it has another effect:

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

Outputs:

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

The Go documentation states:

The deferred call's arguments are evaluated immediately, but the function call is not executed until the surrounding function returns.

So arguments being evaluated, may explain why the Main Value returned is 51 and not 61, since the fmt.Println statements are taking increaseZ as an argument, but defer increaseZ(10) would not be called until after the main function returns.

However, this does not explain why in the first example the increaseZ(10) is outputting before main has completed, and after main has completed in the second example.

I would be grateful if anyone could help me understand what is happening here, since this looks like fertile ground for difficult to diagnose bugs further down the line.

  • 写回答

3条回答 默认 最新

  • duan198409 2015-03-28 14:39
    关注

    You are being inconsistent in your print destination.

    stdout: fmt.Println
    
    stderr: println
    

    Write to the same print destination.

    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
    }
    

    Output:

    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
    

    or,

    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
    }
    

    Output:

    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
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥100 复现论文:matlab仿真代码编写
  • ¥15 esp32驱动GC9A01循环播放视频
  • ¥15 惠普360g9的最新bios
  • ¥30 这个功能用什么软件发合适?
  • ¥60 微信小程序,取消订单,偶尔订单没有改变状态
  • ¥15 用pytorch实现PPO算法
  • ¥15 关于调制信号的星座图?
  • ¥30 前端传参时,后端接收不到参数
  • ¥15 这是有什么问题吗,我检查许可证了但是显示有呢
  • ¥15 机器学习预测遇到的目标函数问题