为什么当annoymouse函数返回时,defer语句的工作方式不同

时间:2019-11-26 04:56:05

标签: go deferred

在这里我声明了一个延迟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

有人可以帮我吗!谢谢

2 个答案:

答案 0 :(得分:1)

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

  

每次执行“ defer”语句时,都会照常评估调用的函数值和参数并重新保存,但不会调用实际函数。取而代之的是,在周围的函数返回之前,立即按照延迟的相反顺序调用延迟的函数。也就是说,如果周围的函数通过显式的return语句返回,则在该return语句设置任何结果参数之后但在函数返回其调用者之前,将执行延迟的函数。如果延迟的函数值计算为nil,则在调用该函数时执行恐慌,而不是在执行“ defer”语句时恐慌。

您的代码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))
    }
}

答案 1 :(得分:0)

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

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 ....
}()