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