为什么延迟语句返回anyymouse函数时会有所不同

问题描述 投票:0回答:2

这里我声明一个延迟trace1的函数

func TestDeferFunc(t *testing.T) {
    fmt.Println("start", time.Now())
    defer trace1()
    time.Sleep(3 * time.Second)
}

func trace1() {
    startTime := time.Now()
    fmt.Println("end time: ", startTime)
    fmt.Println("execute time: ", time.Since(startTime))
}

运行go test -run=^TestDeferFunc$之后,下面是我得到的

start 2019-11-26 12:50:59.59489797 +0800 CST m=+0.000202866
end time:  2019-11-26 12:51:02.595090951 +0800 CST m=+3.000395880
execute time:  49.065µs

但是,当我推迟使用另一个annoymouse函数时,情况发生了变化

func TestDeferFunc(t *testing.T) {
    fmt.Println("start", time.Now())
    defer trace2()()
    time.Sleep(3 * time.Second)
}

func trace2() func() {
    startTime := time.Now()
    fmt.Println("end time: ", startTime)
    fmt.Println("execute time: ", time.Since(startTime))
    return func() {
        fmt.Println("zzz")
    }
}

下面是go test结果

start 2019-11-26 12:52:58.318472958 +0800 CST m=+0.000197852
end time:  2019-11-26 12:52:58.318554368 +0800 CST m=+0.000279262
execute time:  4.853µs
zzz

有人可以帮我吗!谢谢

go deferred
2个回答
1
投票

这是因为defer语句仅defer个被评估的函数调用-并且该函数调用在defer执行时被评估。根据文档:

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred. That is, if the surrounding function returns through an explicit return statement, deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller. If a deferred function value evaluates to nil, execution panics when the function is invoked, not when the "defer" statement is executed. 

您的代码defer trace2()()本质上等于f := trace2(); defer f()。因此trace2立即得到评估(因此被称为)。

因此,为了实现您想要的(跟踪时间),您可以将defer trace3()()trace3()结合使用,如下所示:

func trace3() func() {
    startTime := time.Now()

    return func() {
        fmt.Println("end time: ", time.Now())
        fmt.Println("execute time: ", time.Since(startTime))
    }
}

0
投票

使用延迟跟踪时间的方法是将开始时间传递给延迟函数:

func trace1(startTime time.Time) {
    fmt.Println("start", startTime)
    fmt.Println("end time: ", time.Now())
    fmt.Println("execute time: ", time.Since(startTime))
}

func TestDeferFunc(t *testing.T) {
    defer trace1(time.Now())
    time.Sleep(3 * time.Second)
}

传递的参数将立即执行,但实际的函数调用将延迟到最后。

如果您想更清楚地了解执行什么和推迟什么,可以将整个内容包装在一个函数中,以确保内部的所有内容都在最后执行

defer func() {
    ..... code ....
}()
© www.soinside.com 2019 - 2024. All rights reserved.