背景
在go语言里设计里,普通语言try catch
处理异常的机制,破坏了程序流程控制,降低可读性,与维护成本。
在go里,认为异常(error)应该为函数的返回值,调用方应该在任何时候都要判断函数的返回值是否有异常,再根据结果执行后续的代码。
go基于此特性,go增加了defer, recover可对程序更灵活的流程控制
defer
三种规则:
- defer 的函数的参数为当前参数的快照值,后续如果有对该变量变化,在defer 函数执行时,还是未变化之前的值。相当于参数提前保存。
func a() {
i := 0
defer fmt.Println(i)
i++
return
}
# output
# 0 // not 1
- defer 函数队列,为后进先出队列
func b() {
for i := 0; i < 4; i++ {
defer fmt.Print(i)
}
}
# output
# 3210
- defer 函数里,可以改变命名返回变量的值
func c() (i int) {
defer func() { i++ }()
return 1
}
# output
# 2 // 注意不是1
注意事项
Q: defer队列里的函数,执行产生异常,队列里后面的函数会继续执行吗?
A: defer 设计为资源回收处理动作,保证defer函数队列里的函数,都会被执行
测试例子:https://play.golang.org/p/P7CNK3DNgDf
package main
import "fmt"
func main() {
f()
fmt.Println("returned from func main")
}
func f() {
defer func() {
fmt.Println("defer level 1")
}()
defer func() {
fmt.Println("defer level 2, panicking")
var i = 100
_ = 5 / (i-i)
}()
defer func() {
fmt.Println("defer level 3, panicking")
var i = 100
_ = 5 / (i-i)
}()
fmt.Println("in func f")
fmt.Println("returned from func f")
}
网友评论