Go学习-defer

52 阅读2分钟

defer是Go提供用于注册延迟调用的机制,让函数或语句可以再当前函数执行完成之后(包括return语句正常结束或者panic导致的异常结束)执行。defer常用于资源回收的场景,比如打开/关闭连接,加锁或释放锁等。

不同的defer执行顺序

func main() {
   defer fmt.Println("main defer1")
   test()
   defer fmt.Println("main defer2")
}

func test() () {
   defer func() {
      fmt.Println("test defer1")
   }()
   defer func() {
      fmt.Println("test defer2")
   }()
}

输出结果:

image.png

执行流程:

image.png

defer执行有两个条件:

  1. defer所在的函数必须先执行完成
  2. 按照栈的FILO的方式执行。 因此,test函数先于main函数结束,因此test函数中defer先执行。栈是FILO,因此打印test defer2->test defer1。test函数执行完成之后,main函数执行完成之后,执行main函数的defer操作,同样按照FILO的方式执行,因此打印main defer2->main defer1

defer与return的执行顺序

理解上面defer的执行过程,就很容易理解defer与return的执行顺序

func main() {
    ret := test()
    fmt.Println("test return:", ret)
}

func test() ( int) {
    var i int

    defer func() {
        i++        //defer里面对i增1
        fmt.Println("test defer, i = ", i)
    }()

    return i
}

执行结果:

test defer,i=1
test return: 1

执行顺序:

  1. test函数先执行,test执行返回0,之后执行defer函数,打印test defer,i=1
  2. test函数执行完成之后,main函数打印test return: 0 再来看下面的代码:
func main() {
    ret := test()
    fmt.Println("test return:", ret)
}

//返回值改为命名返回值
func test() (i int) {
    //var i int

    defer func() {
        i++
        fmt.Println("test defer, i = ", i)
    }()

    return i
}

执行结果:

test defer, i =  1
test return: 1

这次test函数的返回值变成了1,defer里面i++修改了返回值,因此defer执行的时机是return之后,但是在返回值返回给调用方之前。