美文网首页
Go语言 defer

Go语言 defer

作者: 小杰的快乐时光 | 来源:发表于2018-08-18 23:16 被阅读0次

参考文章:深入理解Go语言

defer用于资源的释放,会在函数返回之前进行调用

defer关键字的实现跟go关键字很类似,不同的是它调用的是runtime.deferproc而不是runtime.newproc。
在defer出现的地方,插入了指令call runtime.deferproc,然后在函数返回之前的地方,插入指令call runtime.deferreturn。
普通的函数返回时,汇编代码类似:

add xx SP
return

如果其中包含了defer语句,则汇编代码是:

call runtime.deferreturn,
add xx SP
return

goroutine的控制结构中,有一张表记录defer,调用runtime.deferproc时会将需要defer的表达式记录在表中,而在调用runtime.deferreturn的时候,则会依次从defer表中出栈并执行。

实例一:先按照普通函数执行,然后再按照defer 的先进后出逆向执行

func main() {
   fmt.Println("hello world 123")
   defer goodBye()
   defer goodNight()
   goodEating()
   fmt.Println("hello world")
}

func goodNight()  {
   fmt.Println("goodnight")
}
func goodBye()  {
   fmt.Println("goodbye")
}
func goodEating()  {
   fmt.Println("goodeating")
}
---------output-----------
hello world 123
goodeating
hello world
goodnight
goodbye

实例二:若在中间添加一个 return,那么在return之上的,先按照普通函数执行,然后按照defer 的先进后出逆向执行,在return之下的不执行

func main() {
   fmt.Println("hello world 123")
   defer goodBye()
   defer goodNight()
   goodEating()
   return
   fmt.Println("hello world")
}

func goodNight()  {
   fmt.Println("goodnight")
}
func goodBye()  {
   fmt.Println("goodbye")
}
func goodEating()  {
   fmt.Println("goodeating")
}
------output-------
hello world 123
goodeating
goodnight
goodbye

实例三:返回值操作

func f() (result int) {
    defer func() {
        result++
    }()
    return 0
}

由于 return xxx这一条语句并不是一条原子指令!
所以 return xxx 分为 三步操作 :返回值 = xxx ,调用defer函数,空的return,上面代码可以看作下面的代码

func f() (result int) {
     result = 0  //return语句不是一条原子调用,return xxx其实是赋值+ret指令
     func() { //defer被插入到return之前执行,也就是赋返回值和ret指令之间
         result++
     }()
     return
}

实例四:带参数的赋值返回值操作

func f() (r int) {
     t := 5
     defer func() {
       t = t + 5
     }()
     return t
}

上述的return返回的是 t,而我们func的返回值是 r,上面代码可以看作下面的代码

func f() (r int) {
     t := 5
     r = t //赋值指令
     func() {        //defer被插入到赋值与返回之间执行,这个例子中返回值r没被修改过
         t = t + 5
     }
     return        //空的return指令
}

实例五

func f() (r int) {
    defer func(r int) {
          r = r + 5
    }(r)
    return 1
}

分析:

func f() (r int) {
     r = 1  //给返回值赋值
     func(r int) {        //这里改的r是传值传进去的r,不会改变要返回的那个r值
          r = r + 5
     }(r)
     return        //空的return
}

实例六

func main() {
   i := deferRet(1,1)
   println(i)  // print 152
}

func deferRet(x,y int) (z int){
   defer func () { z += 100 }()
   z = x + y  
   return z + 50 // 执行顺序 z = z+50 -> (call defer)z = z+100 -> ret
}

分析:

func deferRet(x,y int) (z int){
   z = x + y // z=2
   z = z+50   //给返回值赋值z=52
  defer z += 100 //z = 150
  return   
}

本质原因是return xxx语句并不是一条原子指令,defer被插入到了赋值 与 ret之间,因此可能有机会改变最终的返回值。

相关文章

  • Go语言学习进度(7)

    1.GO语言关键字Interface 举例说明: 2.GO语言关键字defer

  • Golang学习笔记-defer关键字学习

    defer学习 很多现代的变成语言中都会有defer关键字,Go语言的defer会在当前函数或是方法返回之前执行传...

  • Go语言 defer

    参考文章:深入理解Go语言 defer用于资源的释放,会在函数返回之前进行调用 defer关键字的实现跟go关键字...

  • Go语言——defer

    Go语言——defer defer操作类似stack,FILO先进后出。 与return一直使用的时候,需要注意顺...

  • go语言——defer

    defer

  • golang语言defer特性详解.md

    [TOC] golang语言defer特性详解 defer语句是go语言提供的一种用于注册延迟调用的机制,它可以让...

  • go语言的defer语句

    go语言defer语句的用法 defer的语法 defer后面必须是函数调用语句,不能是其他语句,否则编译器会出错...

  • Go基础笔记

    Go语言基础(一) 流程控制语句:for、if、else、switch、defer for Go只有一种循环结构:...

  • defer

    Go 语言的 defer 会在当前函数或者方法(不是main)返回之前执行函数。由于 defer 的延迟特性,de...

  • go 语言错误处理

    go 语言错误处理 panic recover defer 最大公约数 最小公倍数 go语言中的没有try cat...

网友评论

      本文标题:Go语言 defer

      本文链接:https://www.haomeiwen.com/subject/ymeqiftx.html