面试Go 被defer的几个盲区坑了
卡二条的技术圈
共 5022字,需浏览 11分钟
·
2023-03-03 18:54
关键字
。finally
操作一样,不管发生任何异常,最终都会被执行。package main
import "fmt"
func main() {
function1()
}
func function1() {
fmt.Printf("2")
defer function2()
fmt.Printf("1")
}
func function2() {
fmt.Printf("3")
}
上述代码执行的结果是:
2
1
3
defer的执行顺序是什么样的
defer与return谁先谁后
先来看如下一段代码,最终的执行结果是怎么样的。
func main() {
fmt.Println(demo2())
}
func demo2() int {
defer func() {
fmt.Println("2")
}()
return func() int {
fmt.Println("1")
return 4
}()
}
运行上述代码,得到的结果是:
1
2
4
函数返回之前执行
。这一点毋庸置疑,肯定是在return之前执行。需要注意的是,return 是非原子性的,需要两步,执行前首先要得到返回值 (为返回值赋值),return 将返回值返回调用处。defer 和 return 的执行顺序是先为返回值赋值,然后执行 defer,然后 return 到函数调用处。函数的返回值初始化与defer间接影响
同样的方式,我们先看一段代码,猜测一下最终的执行结果是什么。
func main() {
fmt.Println(demo3())
}
func demo3() (a int) {
defer func() {
a = 3
}()
return 1
}
上诉代码,最终的运行结果如下:
3
func main() {
fmt.Println(demo7())
}
func demo7() int {
var a int
defer func(a int) {
a = 10
}(a)
return 2
}
上述的最终结果返回值如下:
10
2
defer遇见panic。
func main() {
demo4()
}
func demo4() {
defer func() {
fmt.Println("1")
}()
defer func() {
fmt.Println("2")
}()
panic("panic")
defer func() {
fmt.Println("3")
}()
defer func() {
fmt.Println("4")
}()
}
运行上述代码,最终得到的结果如下:
╰─ go run defer.go
2
1
panic: panic
goroutine 1 [running]:
main.demo4()
panic之前定义的defer都会被执行
,所有的 defer 语句都会保证执行并把控制权交还给接收到 panic 的函数调用者。这样向上冒泡直到最顶层,并执行(每层的) defer,在栈顶处程序崩溃,并在命令行中用传给 panic 的值报告错误情况:这个终止过程就是 panicking。defer中包含panic
recover()
进行获取。func main() {
demo5()
}
func demo5() {
defer func() {
fmt.Println("1")
if err := recover(); err != nil {
fmt.Println(err)
}
}()
defer func() { fmt.Println("2") }()
panic("panic")
defer func() { fmt.Println("defer: panic 之后, 永远执行不到") }()
}
上述代码执行的结果如下:
2
1
panic
defer下的函数参数包含子函数
func main() {
demo6()
}
func function(index int, value int) int {
fmt.Println(index)
return index
}
func demo6() {
defer function(1, function(3, 0))
defer function(2, function(4, 0))
}
上诉代码最终执行的结果是:
3
4
2
1
总结
评论