一、异常处理介绍
1、go 中异常处理介绍
- Golang 没有结构化异常。使用 panic 抛出错误,recover 捕获错误
- Go 中可以抛出一个 panic 的异常,然后在 defer 中通过 recover 捕获这个异常,然后正常处理
- panic 可以在任何地方引发,但 recover 只有在 defer 调用的函数中有效
2、panic
- 内置函数
- 假如函数 F 中书写了 panic 语句,会终止其后要执行的代码,在 panic 所在函数 F 内如果存在要执行的 defer 函数列表按照 defer 的逆序执行
- 返回函数 F 的调用者 G,在 G 中,调用函数 F 语句之后的代码不会执行,假如函数 G 中存在要执行的 defer 函数列表,按照 defer 的逆序执行
- 知道 goroutine 整个退出,并报告错误
3、recover
- 内置函数
- 用来控制一个 goroutine 的 panicking 行为,捕获 panic,从而影响应用的行为
- 一般的调用建议
- 在 defer 函数中,通过 recever 来终止一个 goroutine 的 panicking 过程,从而恢复正常代码的执行
- 可以获取通过 panic 传递的 error
4、注意
- 利用 recover 处理 panic 指令,defer 必须放在 panic 之前定义,另外 ercover 只有在 defer 调用的函数中才有效
- 否则当 panic 时,recover 无法捕获到 panic,无法防止 panic 扩散
- recover 处理异常后,逻辑并不会恢复到 panic 那个点去,函数跑到 defer 之后的那个点
- 多个 defer 会形成 defer 栈,后定义的 defer 语句会被最先调用
二、panic/recover 异常处理
1、panic 触发程序崩溃
- 程序运行期间 funcB 中引发 panic 导致程序崩溃,异常退出了
- 这个时候我们就可以通过 recover 将程序恢复回来,继续往后执行
package main
func funcB() {
panic("panic in B")
}
func mian() {
funcB()
}
/*
goroutine 1 [running]:
main.funcB(...)
E:/_000/Go/Code/demo1.go:3
main.main()
E:/_000/Go/Code/demo1.go:6 +0x45
*/
2、defer、recover实现异常处理
- recover()必须搭配 defer 使用
- defer 一定要在可能引发 panic 的语句之前定义
package main
import "fmt"
func funcB(){
defer func() {
if err := recover(); err != nil {
fmt.Println(err) // runtime error: integer divide by zero
}
}()
num1 := 10
num2 := 0
res := num1 / num2
fmt.Println("res=", res)
}
func main() {
funcB()
}
3、defer、panic、recover 抛出异常
package main
import (
"errors"
"fmt"
)
func readFile(fileName string) error {
if fileName == "main.go"{
return nil
}
return errors.New("读取文件错误")
}
func fn3() {
defer func() {
if err := recover(); err !=nil{
fmt.PrintIn(err) //读取文件错误
}
}()
var err = readFile("xxx.go")
if err != nil{
panic(err)
}
fmt.PrintIn("继续执行")
}
func main(){
fn3()
}