概述

延时处理,在 defer 归属的函数即将返回时,将延时处理的语句按照 defer 定义的逆序进行执行,先被 defer 的语句最后被执行。

拦截 panic,使程序回复正常运行;
优雅的关闭资源;
修改函数具名返回值;
输出调试信息;
还原旧变量的值;

执行时机

go 中的 return 不是原子操作,分为给返回值赋值和 ret 两步,而 defer 语句的执行就在返回值赋值操作后,ret 指令执行之前。2586653-a27df95afed90749.webp

  1. func main() {
  2. fmt.Println(test())
  3. }
  4. func test() (res int) {
  5. res = 1
  6. defer func() {
  7. fmt.Println("start", res)
  8. res++
  9. fmt.Println("end", res)
  10. }()
  11. return 7
  12. }
  13. //start 7
  14. //end 8
  15. //8
func calc(index string, a, b int) int {
    ret := a + b
    fmt.Println(index, a, b, ret)
    return ret
}
func main() {
    x := 1
    y := 2
    defer calc("AA", x, calc("A", x, y))
    x = 10
    defer calc("BB", x, calc("B", x, y))
    y = 20
}
// defer注册要延迟执行的函数时该函数所有的参数都需要确定其值
A 1 2 3
B 10 2 12
BB 10 12 22
AA 1 3 4
package main

import "fmt"

func trace(s string) string {
    fmt.Println("entering :", s)
    return s
}

func un(s string) {
    fmt.Println("leaving :", s)
}

func a() {
    defer un(trace("a"))
    fmt.Println("in a")
}

func b() {
    defer un(trace("b"))
    fmt.Println("in b")
    a()
}

func main() {
    b()
}
//entering : b
//in b
//entering : a
//in a
//leaving : a
//leaving : b

使用时的问题

何时使用

append、cap、len、make、new 等内置函数是不可以直接作为 deferred 函数的,而 close、copy、delete、print、recover 等可以。注意 append 和 copy。

这些不可直接使用的可以使用一个包裹他的匿名函数来实现。

defer 关键字的求值时机

defer 关键字后面的表达式是在将 deferred 函数注册到 deferred 函数栈的时候进行求值的。

package main

import "fmt"

func foo1() {
    for i := 0; i < 4; i++ {
        defer fmt.Println(i)
    }
}

func foo2() {
    for i := 0; i < 4; i++ {
        defer func(n int) {
            fmt.Println(n)
        }(i)
    }
}

func foo3() {
    for i := 0; i < 4; i++ {
        defer func() {
            fmt.Println(i)
        }()
    }
}

func main() {
    fmt.Println("foo1: ")
    foo1()
    fmt.Println("foo2: ")
    foo2()
    fmt.Println("foo3: ")
    foo3()
}
//foo1: 
//3
//2
//1
//0
//foo2: 
//3
//2
//1
//0
//foo3: 
//4
//4
//4
//4
package main

import "fmt"

func foo1() {
    sl := []int{1, 2, 3}
    defer func(a []int) {
        fmt.Println(a)
    }(sl)

    sl = []int{3, 2, 1}
    _ = sl
}

func foo2() {
    sl := []int{1, 2, 3}
    defer func(p *[]int) {
        fmt.Println(*p)
    }(&sl)

    sl = []int{3, 2, 1}
    _ = sl
}

func main() {
    foo1()
    foo2()
}

//[1 2 3]
//[3 2 1]