当defer func评估其参数时

时间:2017-03-09 19:18:51

标签: go error-handling 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
    }
}

输出:

2nd defer: defer not error
1st defer: new error

Doc表示在评估延迟调用时会评估参数,这似乎应该是一致的。为什么2 defer对变量err有不同的值,因此输出不同?我知道它与第二个函数有err作为输入参数,但不知道为什么。

3 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:2)

另一种方法是使用对原始 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
    }
}

输出为:

2nd defer: new error
1st defer: new error

答案 2 :(得分:1)

Defer StatementDefer 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)
}

输出:

  

延迟陈述经过时间:3秒

     

延迟功能经过的时间:6s

go play上尝试以上

这是因为在Deferred Statement情况下,立即评估了延迟调用的参数 refer doc