defer + recover + panic使用
一般我们都会用defer捕获panic,但是defer+recover的语法糖是有其需要注意的地方的:
func main() {
funcA()
funcB()
}
func funcA() {
defer func() {
if r := recover(); r != nil {
fmt.Println("func A recover...")
}
}()
panic("panic a test...")
}
func funcB() {
defer func() {
funcRecover()
}()
panic("panic b test...")
}
func funcRecover() {
if r := recover(); r != nil {
fmt.Println("funcRecover ....") // 并没有打印出来,即没有成功捕获panic
}
}
代码运行结果是:
funcA的recover函数成功捕获到了panic。
funcB没有捕获到panic,发生了进程退出。
这是因为Golang语言里对应panic()+defer()+recover()这个语法糖组合起来会有一个潜在的坑:panic的错误只能在当前defer()中调用recover()捕获到,如果有嵌套方法,则recover无法捕获到panic错误,官方对应文档: go.dev/blog/defer-…
defer 传参
func main(){
ctx := context.Background()
var err error
defer normalExec(ctx, err) // 直接调用函数
err = fmt.Errorf("test err")
}
func normalExec(ctx context.Context, err error) {
fmt.Printf("err is %v", err)
}
运行结果是:
func main(){
ctx := context.Background()
var err error
defer func() {
normalExec(ctx, err) // 在匿名函数里调用
}
err = fmt.Errorf("test err")
}
func normalExec(ctx context.Context, err error) {
fmt.Printf("err is %v", err)
}
可以看到,在defer函数里是否用匿名函数对结果的赋值有很大的影响。 假如不使用匿名函数,而是在defer里直接调用函数,即 defer normalExec(...),会导致函数参数先求值,从而导致err恒为nil