在使用 Golang 开发程序时,我们可能会经常使用 defer 关键字,实现资源的回收,以及完成“收尾”工作。
执行顺序
若函数中有多个 defer ,执行顺序为 先进后出 ,可理解为栈。
package mainimport ( "fmt")func main() { for i := 0; i < 3; i++ { defer fmt.Println(i) }}// 2// 1// 0复制代码
参数确定的时机
defer 在声明时会先计算确定其参数的值,推迟执行的仅是其函数体。
package mainimport "fmt"func print(a int) { fmt.Println("value in deferred function", a)}func main() { a := 5 defer print(a) a = 10 fmt.Println("value before deferred function call", a)}// value before deferred function call 10// value in deferred function 5复制代码
在实际开发中,defer 的使用经常伴随着闭包和匿名函数的使用。
package mainimport "fmt"func main() { for i := 0; i < 3; i++ { // i 在每次循环中,都被确定其对应的值:0,1,2 defer fmt.Println(i) }}// 2// 1// 0复制代码
package mainimport "fmt"func main() { for i := 0; i < 3; i++ { // 由于函数体只是被延迟执行,故在执行 defer 时, // i 的值为 3 defer func() { fmt.Println(i) }() }}// 3// 3// 3复制代码
return
在调用 return 时,会完成以下的事情:
- 对返回值赋值
- 调用 defer 表达式
- 退出函数,并将返回值给调用函数
package mainimport ( "fmt")// 匿名返回值func func_naked_return() int { defer func() { fmt.Println("由于无法获取到匿名返回值变量,故无法对其进行修改") }() fmt.Println("对返回值赋值") return 1}// 匿名返回值func func_naked_return_pointer() *int { var r int defer func() { r++ fmt.Println("由于返回类型为指针,故可通过修改 r 间接修改匿名返回值") }() fmt.Println("对返回值赋值") return &r}// 命名返回值func func_named_return() (r int) { defer func() { fmt.Println("在调用 defer 表达式时,已完成对返回值的赋值 ", r) r = 2 }() fmt.Println("对返回值赋值") return 1}func main() { fmt.Println("退出函数,将返回值给调用函数 ", func_naked_return()) fmt.Println("-------") fmt.Println("退出函数,将返回值给调用函数 ", func_named_return()) fmt.Println("-------") fmt.Println("退出函数,将返回值给调用函数 ", *func_naked_return_pointer())}// 对返回值赋值// 由于无法获取到匿名返回值变量,故无法对其进行修改// 退出函数,将返回值给调用函数 1// -------// 对返回值赋值// 在调用 defer 表达式时,已完成对返回值的赋值 1// 退出函数,将返回值给调用函数 2// -------// 对返回值赋值// 由于返回类型为指针,故可通过修改 r 间接修改匿名返回值// 退出函数,将返回值给调用函数 1复制代码
- 匿名返回值变量无法被 defer 表达式所获取,故 defer 无法直接修改匿名返回值。但在返回值为指针类型的情况下,可通过修改指针所指向的值,实现间接修改匿名返回值
作用域
- 当任意一条(主)协程发生 panic 时,会执行当前协程中 panic 之前已声明的 defer
- 主动调用
os.Exit(int)
时,defer 将不执行 - 在发生 panic 的(主)协程中,若没有一个 defer 调用
recover()
进行修复,则在执行完之前已声明的 defer 后,进程崩溃 - defer 只对当前的(主)协程有效