一、定义

defer 是一种关键字,用于在函数返回前执行一些操作。

defer 语句可以将一个函数调用推迟到当前函数返回之前执行。

defer 语句可以在函数内部的任何地方定义,并且可以定义多个 defer 语句。当函数返回时,defer 语句会按照后进先出(LIFO)的顺序执行,即最后定义的 defer 语句最先执行。

二、代码示例

package main

import "fmt"

func main() {

   // defer 的执行顺序与定义顺序相反,最先声明的最后执行
   defer fmt.Println("我是1")
   defer fmt.Println("我是2")
   defer fmt.Println("我是3")

   fmt.Println("我是4")
}

打印结果

我是4
我是3
我是2
我是1

defer也可以修饰函数,意为可以将一个函数调用推迟到当前函数返回之前执行。

但是注意defer 语句不是延迟执行语句。它并不会使函数内部的语句推迟执行,而只是将某个函数调用推迟到函数返回之前执行。

package main

import "fmt"

func main() {

   a := 1
   b := 2

   defer func() {
      fmt.Println("defer1 => a+b=", a+b)
   }()

   defer func(a, b int) {
      fmt.Println("defer2 => a+b=", a+b)
   }(a, b)

   a = 2

   fmt.Println("main")
}

打印:

main
defer2 => a+b= 3
defer1 => a+b= 4

在main中写了两个匿名函数,第一个是闭包获取变量,第二个是函数传参

但是它俩的结果是不一样的,这也是印证了上面的 defer可以将一个函数调用推迟到当前函数返回之前执行

defer func() {
      fmt.Println("defer1 => a+b=", a+b)
   }()

该匿名函数为闭包获取参数,是引用传递,所以对该函数来说,内部的a和b是main函数中a和b的地址引用。

 defer func(a, b int) {
      fmt.Println("defer2 => a+b=", a+b)
   }(a, b)

由于a,b在之前已经赋值了1和2,因此当程序执行到此处时,该匿名函数已经完成了它的定义,它内部只认a=1,b=2,因此这种传参是值复制。

总结:defer 调用的函数,参数的值在 defer 定义时就确定了,看下代码

defer fmt.Println(a + b),在这时,参数的值已经确定了。

而 defer 函数内部所使用的变量的值需要在这个函数运行时才确定,看下代码

defer func() { fmt.Println(a + b) }(),a 和 b 的值在函数运行时,才能确定。

三、打断施法

当程序使用**os.Exit()**时,程序会直接退出,而deferreturn也不会被执行。

package main

import (
   "fmt"
   "os"
)

func main() {

   defer fmt.Println("执行defer")

   fmt.Println("main")

   a := func() int {
      os.Exit(0)
      return 1
   }()

   fmt.Println("a:", a)
}

打印:

main