为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕哥9229398 2023-08-07 14:54:06
这里我声明了一个推迟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.000202866end time:  2019-11-26 12:51:02.595090951 +0800 CST m=+3.000395880execute 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.000197852end time:  2019-11-26 12:52:58.318554368 +0800 CST m=+0.000279262execute time:  4.853µszzz有人可以帮我吗!谢谢
查看完整描述

2 回答

?
三国纷争

TA贡献1804条经验 获得超7个赞

这是因为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))

    }

}


查看完整回答
反对 回复 2023-08-07
?
哆啦的时光机

TA贡献1779条经验 获得超6个赞

使用 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 ....

}()


查看完整回答
反对 回复 2023-08-07
  • 2 回答
  • 0 关注
  • 101 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信