go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理。
一、go的defer
1.1 go defer 介绍
defer后边会接一个函数,但该函数不会立刻被执行,而是等到包含它的程序返回时(包含它的函数执行了return语句、运行到函数结尾自动返回、对应的goroutine panic)defer函数才会被执行。通常用于资源释放、打印日志、异常捕获等
1.2 多个go defer 的执行顺序
go的defer函数,调用顺序类似于
栈
,越后面的defer函数越先被执行(后进先出
)
func main() {
defer fmt.Printf("我")
defer fmt.Printf("是")
defer fmt.Printf("三")
defer fmt.Printf("火")
}
输出结果:
火三是我
1.3 go defer 最佳实践
✅ 推荐
import (
"fmt"
"io"
"os"
)
func main() {
// 打开文件
// fp, err := os.Open("./test.txt") // 只读方式打开
fp, err := os.OpenFile("./test.txt", os.O_CREATE|os.O_APPEND, 6) // 读写方式打开
if err!=nil {
// 错误处理
}
defer fp.Close() //如果成功打开了文件,就关闭文件,释放资源。
doSomething(A) // 做了A事情
doSomething(B) // 做了B事情
doSomething(C) // 做了C事情
return
}
❌ 不推荐
import (
"fmt"
"io"
"os"
)
func main() {
// 打开文件
// fp, err := os.Open("./test.txt") // 只读方式打开
fp, err := os.OpenFile("./test.txt", os.O_CREATE|os.O_APPEND, 6) // 读写方式打开
if err!=nil {
// 错误处理
}
doSomething(A) // 做了A事情
doSomething(B) // 做了B事情
doSomething(C) // 做了C事情
defer fp.Close() //关闭文件,释放资源。这里写着写着可能就忘了关了。
return
}
二、go panic
2.1 go panic 介绍
1、内建函数
2、假如函数F中书写了panic语句,会终止其后要执行的代码,在panic所在函数F内如果存在要执行的defer函数列表,按照defer的逆序执行
3、返回函数F的调用者G,在G中,调用函数F语句之后的代码不会执行,假如函数G中存在要执行的defer函数列表,按照defer的逆序执行,这里的defer 有点类似 try-catch-finally 中的 finally
4、直到goroutine整个退出,并报告错误
三、go recover
3.1 go recover 介绍
1、内建函数
2、用来控制一个goroutine的panicking行为,捕获panic,从而影响应用的行为
3、一般的调用建议
a). 在defer函数中,通过recever来终止一个gojroutine的panicking过程,从而恢复正常代码的执行
b). 可以获取通过panic传递的error
3.2 go panic recover 最佳实践
❌ 不推荐
// 使用error的写法
func first() error {return nil}
func second() error {return nil}
func third() error {return nil}
func fourth() error {return nil}
func fifth() error {return nil}
func Do() error {
var err error
// 套娃
if err = first(); err == nil {
if err = second(); err == nil {
if err = third(); err == nil {
if err = fourth(); err == nil {
if err = fifth(); err == nil {
return nil
}
}
}
}
}
return err
}
✅ 推荐
// panic 写法
func Do2() (err error) {
defer func(){
if r:= recover() ; r!= nil{
err = fmt.Errorf("Error: %+v", r)
}
}()
first2()
second2()
third2()
fourth2()
fifth2()
return
}