当defer func评估其参数时

Yul*_*ong 7 error-handling go deferred

我正在学习delang中的延迟行为,并希望在函数返回时使用它来处理错误.

代码如下:

package main

import "fmt"
import "errors"

func main() {
    a()
}

func a() {
    var err error   
    defer func(){
        if err != nil {
            fmt.Printf("1st defer: %s\n", err)
        } else {
            fmt.Println("1st defer: defer not error")
        }
    }()
    defer func(err error){
        if err != nil {
            fmt.Printf("2nd defer: %s\n", err)
        } else {
            fmt.Println("2nd defer: defer not error")
        }
    }(err)

    err = errors.New("new error")
    if err != nil {
        return
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

2nd defer: defer not error
1st defer: new error
Run Code Online (Sandbox Code Playgroud)

Doc表示在评估延迟呼叫时评估参数,这似乎应该是一致的.为什么2推迟对于变量err和不同的输出具有不同的值?我知道它与第二个函数有关,err作为输入参数,但不知道为什么.

Hub*_*rtS 9

另一种方法是使用对原始err变量的引用

package main

import (
    "errors"
    "fmt"
)

func main() {
    a()
}

func a() {
    var err error
    defer func() {
        if err != nil {
            fmt.Printf("1st defer: %s\n", err)
        } else {
            fmt.Println("1st defer: defer not error")
        }
    }()
    defer func(err *error) {
        if *err != nil {
            fmt.Printf("2nd defer: %s\n", *err)
        } else {
            fmt.Println("2nd defer: defer not error")
        }
    }(&err)

    err = errors.New("new error")
    if err != nil {
        return
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是:

2nd defer: new error
1st defer: new error
Run Code Online (Sandbox Code Playgroud)


aru*_*007 9

Defer Statement在和 的情况下还有另一种类似的情况Defer Function。请看下面的例子

package main

import (
    "fmt"
    "time"
)

func main() {

    start := time.Now()
    time.Sleep(3*time.Second)
    defer func() { fmt.Println("Defer Function Elapsed Time: ", time.Since(start)) }() //Defer Function
    defer fmt.Println("Defer Statement Elapsed Time: ", time.Since(start)) //Defer Statement
    time.Sleep(3*time.Second)
}
Run Code Online (Sandbox Code Playgroud)

输出:

延迟语句运行时间:3s

延迟功能运行时间:6s

在go play中尝试上面的操作

这是因为在Deferred Statement延迟调用的参数立即评估的情况 下,请参阅文档


Yul*_*ong 8

好吧,我刚想通了.如果将任何参数传递给延迟函数(如上面的第二个延迟函数),则在延迟函数延迟时评估这些参数,而不是在执行它们时.这意味着在我的示例err中仍然存在nil并且尚未分配给新错误.

另一方面,在上面的第1个推迟中,err不是参数,而是函数中的变量a,并且当执行第1个延迟时,它已经被分配给新的错误.