分享
  1. 首页
  2. 文章

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

memo012 · · 750 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

该文章始发于公众号【迈莫coding】

链接: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 func
defer func

结论

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

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

示例

package main
import "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 main
import "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 main
import "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() 执行2
defer: panic() 执行1
panic: 发生异常
// 异常信息...

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

示例

package main
import "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() 执行2
defer: panic() 执行1
发生异常
main函数执行完成

练习:defer面试题

  1. 下面代码输出什么?
package main
import "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 
  1. 程序运行结果

示例

package main
import (
 "fmt"
)
func main() {
 defer_call()
}
func defer_call() {
 defer func() { fmt.Println("迈") }()
 defer func() { fmt.Println("莫") }()
 defer func() { fmt.Println("coding") }()
}

考点

defer和函数组合调用方式 

结果

coding
莫
迈
  1. 下面代码输出什么?

示例

package main
import "fmt"
func DeferFunc1(i int) (t int) {
 t = i
 defer func() {
 t += 3
 }()
 return t
}
func main() {
 fmt.Println(DeferFunc1(1))
}

考点

defer和函数组合调用方式 

结果

4

执行过程

1. 将返回值t赋值为行参i,t = 1
2. 执行return语句,将t 赋值给t
3. 执行defer语句,t + 3 = 4
4. 返回值4
  1. 下面代码输出什么?

示例

package main
import "fmt"
func DeferFunc2(i int) int {
 t := i
 defer func() {
 t += 3
 }()
 return t
}
func main() {
 fmt.Println(DeferFunc2(1))
}

考点

defer和函数组合调用方式 

结果

1

执行过程

1. 创建变量t并将其赋值为i的值,t = 1
2. 执行return语句,注意这里是将t赋值给返回值,此时返回值为1(这个返回值并不是t)
3.执行defer语句,t = t + 3 = 4
4. 函数返回值1
  1. 下面代码输出什么?

示例

package main
import "fmt"
func DeferFunc3(i int) (t int) {
 defer func() {
 t += i
 }()
 return 2
}
func main() {
 fmt.Println(DeferFunc3(1))

考点

defer和函数组合调用方式 

结果

3

执行过程

1. 首先将t赋值为2
2. 执行defer语句,t = t + 1 = 3
3. 函数返回值3
  1. 下面代码输出什么?

示例

package main
import "fmt"
func DeferFunc4() (t int) {
 defer func(i int) {
 fmt.Println(i)
 fmt.Println(t)
 }(t)
 t = 1
 return 2
}
func main() {
 DeferFunc4()
}

考点

defer和函数组合调用方式 

结果

0
2

执行过程

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

闲聊

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

欢迎加入我的公众号【迈莫coding】 一起pk大厂

  • 迈莫coding欢迎客官的到来

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
750 次点击 ∙ 1 赞
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏