defer 的实现原理是,将defer函数直接插入到函数末尾,将defer函数在当前函数内展开并直接调用

defer特性:

  1. 延迟特性:defer后的函数不会立即执行,而是延迟到函数结束后执行
  2. 参数预计算:defer后的函数的参数会立即求值,并固定下来,不会等到函数执行的时候再将参数传递到defer中

    比如:

    import "fmt"
    
    func main() {
        a := 1
        defer func(a int) {
            fmt.Println(a)
        }(a +1)
        a = 100
    }

    会在执行到该defer的时候,计算a+1=2,然后把2当作参数固定下来,最后在函数返回前,执行defer函数内的语句,所以输出的是:2

  3. 执行顺序:按先进后出的顺序执行defer函数

    比如:

    import "fmt"
    
    func main() {
        defer func() {
            fmt.Println(111)
        }()
        defer func() {
            fmt.Println(222)
        }()
        defer func() {
            fmt.Println(333)
        }()
        defer func() {
            fmt.Println(444)
        }()
    }

    输出为:

    444
    333
    222
    111
  4. 返回值陷阱:

    return包含了下面几步:将返回值保存在栈上-》执行defer函数-〉函数返回

    比如:

    func deferReturn1() (r int) {
        defer func() {
            g = 200
        }()
        return g
    }
    func deferReturn2() (r int) {
        r = g
        defer func() {
            r = 200
        }()
        return r
    }
    
    func TestDeferReturn(t *testing.T) {
        t.Log(deferReturn1())
        t.Log(deferReturn2())
    }
    
    //输出
    index_test.go:65: 100
    index_test.go:66: 200

    deferReturn1中,先计算了返回值并保存在栈上,此时r=100,再执行defer将g=200,实际返回的r则还是100

    deferReturn2中,先将r=g,计算了返回值保存在栈上,此时r=100,再执行defer将r=200,最终返回的r为200

其他特点:

  1. panic之后的defer不会被执行
  2. panic没有recover时,抛出的panic到当前的grouting最上层函数时,最上层函数直接终止
  3. 当panic被捕获之后,当前gorouting上层函数正常执行
  4. 在panic之前定义的defer,会在panic之前执行

    func TestDefer(t *testing.T) {
        defer func() {
            fmt.Println("c")
        }()
        panic("b")
        fmt.Println("TestDefer")
    }
    
    //输出
    c
    --- FAIL: TestDefer (0.00s)
    panic: b [recovered]
        panic: b

标签: defer

添加新评论