go那些事儿|defer必掌握知识


本文摘自网络,作者,侵删。

目录

  • defer执行时机
  • defer执行顺序
  • defer与return谁先谁后
  • 函数包含多个Panic,defer中recover处理那个Panic
  • 函数返回值遇到defer
  • defer遇到Panic
    • defer遇到Panic,但是并不捕获异常的情况
    • defer遇到Panic,并捕获异常
  • 练习:defer面试题
  • 闲聊
  • 欢迎加入我的公众号【迈莫coding】 一起pk大厂

defer执行时机

  • return 语句执行完之后,如果有 defer 语句,再执行 defer 语句
  • 发生 Panic ,也会触发 defer 执行

defer执行顺序

多个defer出现时,会以"先进后出,后进先出"的规则来执行,类似于数据结构中栈的执行顺序.

示例:

package main 

import "fmt"func main() {  defer func(){
    fmt.Println("A")
  }()  defer func(){
    fmt.Println("B")
  }  defer func(){
    fmt.Println("C")
  }
}复制代码

结果:

C
B
A复制代码

defer与return谁先谁后

示例代码

package main 

import "fmt"func deferFunc() {
  fmt.Println("defer func")
}func returnFunc() int {
  fmt.Println("return func")  return 1}func returnAndDefer() int {  defer deferFunc()  return returnFunc()
}func main() {
  returnAndDefer()
}复制代码

结果

return funcdefer func复制代码

结论

一个函数中即有return语句,也有defer语句,先执行return语句,后执行defer语句复制代码

函数包含多个Panic,defer中recover处理那个Panic

示例

package mainimport "fmt"func main() {  defer func() {if err := recover(); err != nil {
      fmt.Println(err)
    }else {
      fmt.Println("fail")
    }
  }()  defer func() {panic("defer panic")
  }()  panic("main panic")
}复制代码

结果

defer panic复制代码

结论

只有最后一个panic,可以被recover捕获到.复制代码

函数返回值遇到defer

示例

package mainimport "fmt"func deferFunc() (t int) { // t初始化为0,并且作用域为该函数全域
  defer func() {
    t = t * 10
  }()  return 1}func main() {
  fmt.Println(deferFunc())
}复制代码

结果

10 复制代码

结论

当调用deferFunc()函数时,本应该返回值1,但函数中还有defer语句,
所以在return语句之后,又被defer的匿名函数func函数执行,所以t=t*10被执行。因此返回值为10.复制代码

defer遇到Panic

defer遇到Panic,但是并不捕获异常的情况

示例

package mainimport "fmt"func defer_panic() {  defer func() {
    fmt.Println("defer: panic() 执行1")
  }()  defer func() {
     fmt.Println("defer: panic() 执行2")
  }  panic("发生异常")
  fmt.Println("该条语句无法执行")
}func main() {
  defer_panic()
  fmt.Println("main函数执行完成")
}复制代码

结果

defer: panic() 执行2defer: panic() 执行1panic: 发生异常// 异常信息...复制代码

defer遇到Panic,但捕获异常的情况

示例

package mainimport "fmt"func defer_panic() {  defer func() {
    fmt.Println("defer: panic() 执行1")if err := recover(); err != nil {
      fmt.Println(err)
    }
  }()  defer func() {
     fmt.Println("defer: panic() 执行2")
  }  panic("发生异常")
  fmt.Println("该条语句无法执行")
}func main() {
  defer_panic()
  fmt.Println("main函数执行完成")
}复制代码

结果

defer: panic() 执行2defer: panic() 执行1发生异常
main函数执行完成复制代码

练习:defer面试题

1. 下面代码输出什么?

package mainimport "fmt"func main() {   var name = "zhangsan"
   fmt.Println(name)   defer fmt.Println(name)
   name = "lisa"
   fmt.Println(name)   defer fmt.Println(name)
}复制代码

考点

defer和函数组合调⽤方式 
复制代码

结果

zhangsan lisa lisa zhangsan 
复制代码

2. 程序运行结果

示例

package mainimport (   "fmt")func main() {
   defer_call()
}func defer_call() {   defer func() { fmt.Println("迈") }()   defer func() { fmt.Println("莫") }()   defer func() { fmt.Println("coding") }()
}复制代码

考点

defer和函数组合调⽤方式 
复制代码

结果

coding
莫
迈复制代码

3. 下面代码输出什么?

示例

package mainimport "fmt"func DeferFunc1(i int) (t int) {
    t = idefer func() {
        t += 3}()return t
}func main() {
    fmt.Println(DeferFunc1(1))
}复制代码

考点

defer和函数组合调⽤方式 
复制代码

结果

4复制代码

执行过程

1. 将返回值t赋值为行参i,t = 12. 执行return语句,将t 赋值给t3. 执行defer语句,t + 3 = 44. 返回值4复制代码

4. 下面代码输出什么?

示例

package mainimport "fmt"func DeferFunc2(i int) int {
    t := idefer func() {
        t += 3}()return t
}func main() {
    fmt.Println(DeferFunc2(1))
}复制代码

考点

defer和函数组合调⽤方式 
复制代码

结果

1复制代码

执行过程

1. 创建变量t并将其赋值为i的值,t = 12. 执行return语句,注意这里是将t赋值给返回值,此时返回值为1(这个返回值并不是t)3.执行defer语句,t = t + 3 = 44. 函数返回值1复制代码

5. 下面代码输出什么?

示例

package mainimport "fmt"func DeferFunc3(i int) (t int) {defer func() {
        t += i
    }()return 2}func main() {
    fmt.Println(DeferFunc3(1))
}复制代码

考点

defer和函数组合调⽤方式 
复制代码

结果

3复制代码

执行过程

1. 首先将t赋值为22. 执行defer语句,t = t + 1 = 33. 函数返回值3复制代码

6. 下面代码输出什么?

示例

package mainimport "fmt"func DeferFunc4() (t int) {defer func(i int) {
        fmt.Println(i)
        fmt.Println(t)
    }(t)
    t = 1return 2}func main() {
    DeferFunc4()
}复制代码

考点

defer和函数组合调⽤方式 
复制代码

结果

02复制代码

执行过程

1. 初始化返回值t为零值 02. 首先执行defer的第一步,赋值defer中的func入参t为03. 执行defer的第二步,将defer压栈4. 将t赋值为15. 执行return语句,将返回值t赋值为26. 执行defer的第三步,出栈并执行7. 因为在入栈时defer执行的func的入参已经赋值了,此时它作为的是一个形式参数,所以打印为0;8. 相对应的因为最后已经将t的值修改为2,所以再打印一个2复制代码

闲聊

  • 读完文章,自己是不是和defer的cp率又提高了
  • 我是迈莫,欢迎大家和我交流

原创不易,觉得文章写得不错的小伙伴,点个赞???? 鼓励一下吧~



本文来自:51CTO博客

感谢作者:mb6008e9b926b5d

查看原文:go那些事儿|defer必掌握知识

相关阅读 >>

Gocn酷Go推荐】Go 类型转换神器 cast库

Golang 原子操作

Golang 编码转换解决方案

手撸Golang etcd raft协议之3

tidb-lite: 用于 Golang 数据库相关代码的单元测试

04 Golang数据类型

Golang cGo是什么

.Go是什么文件

Golang如何获取目录下文件是否存在

Golang实现选择排序

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...