深入理解Golang中的defer关键字
对于defer的简单用法,可以参考之前的随笔!!!
本次将详细介绍defer,以及其底层实现,具体的应用场景!!!
Go语言的defer会在当前函数或者方法返回之前执行传入的函数。它会经常被用于关闭文件,关闭数据库连接以及解锁资源。
这里提出两个问题:
1.defer关键字调用时机以及多次调用defer时的知心顺序是如何确定的
2.defer关键字使用传值的方式传递参数时会进行预计算,导致不符合预期的结果
作用域
向defer关键字传入的函数会在函数返回之前运行。这里看两个例子
package main
import "fmt"
func main() {
{
defer println("defer ends")
fmt.Println("block ends")
}
fmt.Println("main ends")
}
输出结果
block ends
main ends
defer ends
import "fmt"
func main() {
{
defer println("defer ends")
fmt.Println("block ends")
}
fmt.Println("main ends")
}
输出结果:
4
3
2
1
0
defer传入的函数不是在提出代码块的作用域执行,只会在当前函数或者方法返回之前被调用。
数据结构(摘自go语言设计与实现)

部分参数说明:
siz:参数和结果的内存大小
sp和pc:分别代表栈指针和调用方法的程序计数器
fn:defer关键字传入的函数
_panic:触发延迟调用的结构体,可能为空
运行过程
defer关键字的运行时实现分成两个部分:
runtime.deferproc:函数负责新的延迟调用
runtime.deferreturn:函数负责在函数调用结束时执行所有的延迟调用
runtime.deferproc会为defer创建一个新的runtime._defer结构体,设置它的函数指针fn,程序计数器sp和栈指针pc并将相关参数拷贝到相邻的内存空间中。
runtime.deferreturn 会从 Goroutine 的 _defer 链表中取出最前面的 runtime.jmpdefer 函数传入需要执行的函数和参数
来看一下《go语言设计与实现》给的关于defer的总结:


浙公网安备 33010602011771号