首页  

go defer 延迟函数     所属分类 go 浏览量 102
defer 用于延迟函数调用,每次defer把函数压入栈中,主函数返回前把延迟的函数取出并执行
栈 后进先出 
创建defer的函数称为主函数,defer语句后面的函数称为延迟函数

延迟函数可能有输入参数,这些参数可能来源于定义defer的函数
也可能引用主函数用于返回的变量,延迟函数可能会影响主函数的一些行为

defer行为规则
延迟函数的参数在defer时已经确定了
延迟函数基于栈,后进先出 ,执行按后进先出顺序执行,即先出现的defer最后执行
延迟函数可能操作主函数的具名返回值,可能会影响返回值


函数返回过程
关键字return不是一个原子操作,实际上return只代理汇编指令ret,即将跳转程序执行
比如语句return i,实际上分两步进行,即将i值存入栈中作为返回值,然后执行跳转,
而defer的执行时机正是跳转前,defer执行时有机会操作返回值

申请资源后立即使用defer关闭资源是好习惯


func deferFuncParameter() { var aInt = 1 defer fmt.Println(aInt) aInt = 2 return } 延迟函数fmt.Println(aInt) 参数在defer时已经确定 输出1 package main import "fmt" func printArray(array *[3]int) { for i := range array { fmt.Println(array[i]) } } func deferFuncParameter() { var aArray = [3]int{1, 2, 3} defer printArray(&aArray) aArray[0] = 10 return } func main() { deferFuncParameter() } 输出10 2 3三个值 延迟函数printArray()的参数在defer时已经确定,即数组的地址 延迟函数执行时机是在return语句之前,对数组的最终修改值会被打印出来 func deferFuncReturn() (result int) { i := 1 defer func() { result++ }() return i } 输出2 延迟函数操作主函数的具名返回值
defer实现原理 defer数据结构 src/src/runtime/runtime2.go type _defer struct { sp uintptr //函数栈指针 pc uintptr //程序计数器 fn *funcval //函数地址 link *_defer //指向自身结构的指针,用于链接多个defer } defer的数据结构跟一般函数类似,也有栈地址、程序计数器、函数地址等 与函数不同的一点是它含有一个指针,可用于指向另一个defer, 每个goroutine数据结构中实际上也有一个defer指针,该指针指向一个defer的单链表, 每次声明一个defer时就将defer插入到单链表表头 每次执行defer时就从单链表表头取出一个defer执行 新声明的defer总是添加到链表头部 函数返回前执行defer则是从链表首部依次取出执行
完整代码 https://gitee.com/dyyx/hellocode/blob/master/web/tech/go/demo/deferdemo.go package main import "fmt" func main() { // 参数在defer时已经确定 输出 1 deferFuncParameter() // 10 2 3 , 参数(数组地址)在defer时已经确定 ,通过指针修改值 deferFuncParameter2() result := deferFuncReturn() // defer 操作命名返回值 ,返回2 fmt.Println(result) } func deferFuncParameter() { var aInt = 1 defer fmt.Println(aInt) aInt = 2 return } func printArray(array *[3]int) { for i := range array { fmt.Print(array[i]," ") } fmt.Print("\n") } func deferFuncParameter2() { var aArray = [3]int{1, 2, 3} defer printArray(&aArray) aArray[0] = 10 return } func deferFuncReturn() (result int) { i := 1 defer func() { result++ }() return i }

上一篇     下一篇
cannot find GOROOT directory

自定义springboot starter

springboot禁用特定的自动配置类

java NIO http server

http request to javabean

数据对象转换Object mapping