golang defer学习与思考

作者: Lucas_Ye | 来源:发表于2017-01-03 18:35 被阅读186次

网上内容摘录学习

defer基础使用

此段落参考 https://my.oschina.net/chai2010/blog/140065

  1. 资源回收,比如file,mutex
f, err := os.Open("file")
if err != nil {
      panic(err)
}
defer f.Close()
mu.Lock()
defer mu.Unlock()
  1. panic的捕获
defer func() { 
      if r := recover(); r != nil { 
         fmt.Println("Recovered in f", r) 
      }
}()
  1. 返回值的修改
func F() (i int) {
     defer func() {
        i++
     }()
     return 1
}   // 返回值为2

defer的实际调用时机

此段落参考 https://tiancaiamao.gitbooks.io/go-internals/content/zh/03.4.html

defer是在return之前执行的。

这是官方原话说的,实际上,
这个return应该分三个步骤:

返回值 = xxx
调用defer函数
空的return

举个例子:

func f() (i int) {
     j := 1
     defer func() {
       j = j + 1
     }()
     return j
}
  • i = j
  • j = j + 1
  • return
    所以,函数的返回值实际是1

defer三大特性

此段落参考 https://my.oschina.net/chai2010/blog/119216

  1. 当defer调用函数的时候, 函数用到的每个参数和变量的值也会被计算
    在这个例子中, 表达式"i"的值将在defer fmt.Println(i)
    时被计算. Defer将会在 当前函数返回的时候打印"0"
func a() {
      i := 0 
      defer fmt.Println(i) 
      i++ 
      return
}
  1. Defer调用的函数将在当前函数返回的时候, 以后进先出的顺序执行.
    下面的函数将输出"3210":
func b() {
      for i := 0; i < 4; i++ {
          defer fmt.Print(i) 
      }
}
  1. Defer调用的函数可以在返回语句执行后读取或修改命名的返回值.
    在这个例子中, defer语句将会在当前函数返回后将i增加1. 实际上, 函数会返回2:
func c() (i int) {
      defer func() {
          i++ 
      }() 
      return 1
}

学习后的思考

主要是对特性1的思考

当defer调用函数的时候, 函数用到的每个参数和变量的值也会被计算

主要是考虑,指针传入的情况
直接上代码:

func F1() {
   var a *int
   var c int = 6
   a = &c
   defer func(a *int) {
      fmt.Println(*a)
   }(a)
   var b int = 5
   a = &b
}  // 此时打印的是:6
  • 此段代码中,defer调用时,a指针指向的是c的地址,
    后面再改变a的地址,defer中已经存起来的a的地址都不会改变了。
    相当于a把地址拷贝给了defer中的备份a。
func F2() {
   var a *int
   var c int = 6
   a = &c
   defer func() {
      fmt.Println(*a)
   }()
   var b int = 5
   a = &b
}  // 此时打印的是:5
  • 此段代码中,defer直接使用了a的地址,是a在return时候,所指向的实际地址。
func F3() {
   var a int = 0
   defer func(a *int) {
      fmt.Println(*a)
   }(&a)
   a = 5
}  // 此时打印的是:5
  • 此段代码中,传入了a的地址,后面修改该地址上的值,是会起作用的。

另外两个小点:

  1. defer是会稍微消耗性能,大概100~200ns
  2. defer在panic的情况下,也会调用的

补充:
在学习effect go时,学习到:
defer中参数是函数时,该函数会先执行

func main() {
   T11()
}
func T11() {
   s := "a"
   defer T12(T13(s))
   fmt.Println("T11", s)
}
func T12(s string) string {
   fmt.Println("T12", s)
   return s
}
func T13(s string) string {
   fmt.Println("T13", s)
   return s
}

// 结果
T13 a
T11 a
T12 a

相关文章

  • golang defer学习与思考

    网上内容摘录学习 defer基础使用 此段落参考 https://my.oschina.net/chai2010/...

  • Golang之Defer

    引用 golang defer实现原理 Golang之轻松化解defer的温柔陷阱 Golang中defer、re...

  • 2017-12-04

    Golang,Panic,Defer,Recover 在golang中,recover在defer里发挥作用。 一...

  • golang学习--defer

    Go 语言中的 defer 语句,可以在函数结束或者是出现异常时保证执行相关释放资源的操作,和 C++中的析构函数...

  • go defer理解

    golang的defer是怎么工作的?defer在golang里是一个很基础的关键字,在函数内部使用defer声明...

  • golang中defer执行时机与常见问题

    defer是什么? defer的用途 defer的执行时机 了解defer的执行时机首先要知道golang的ret...

  • 聊聊golang的defer

    序 本文主要研究一下golang的defer defer return先赋值(对于命名返回值),然后执行defer...

  • 12 Golang defer panic recover

    defer Golang中的defer会将其后面跟随的语句进行延迟处理。在defer归属的函数即将返回时,将延迟处...

  • 2017-11-23 step

    1 Golang的返回值,return,defer 多个defer的顺序是stack顺序,FILO 正确的顺序是:...

  • Golang defer

    话题起于同事在微信群里发了张图,是Go Newsletter于13日在Twitter上转的一个代码截图,问输出是啥...

网友评论

    本文标题:golang defer学习与思考

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