go defer 延迟函数
所属分类 go
浏览量 887
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