什么是异常?
不按照我们期望执行的都可以称之为异常
在Go语言中如何处理异常?
- 一种是程序发生异常时, 将异常信息反馈给使用者
- 一种是程序发生异常时, 立刻退出终止程序继续运行
将异常信息反馈给使用者
- 创建方式一:
fmt.Errorf("提示的内容")
- 创建方式二:
errors.New("提示的内容")
注意点: 本质上两个方法底层的实现原理都是一样的
package builtin中定义了一个接口
type error interface { Error() string }
package errors中定义了一个结构体
type errorString struct { s string }
errorString结构体实现了builtin中定义的接口
func (e *errorString) Error() string { return e.s }
所以errorString结构体实现了error接口
func New(text string) error { return &errorString{text} }
异常信息提示
func TestThrowError(t *testing.T) { if res, err := div(10, 0); err == nil { fmt.Println(res) } else { fmt.Println(err) } } func div(a int, b int) (res int, err error) { if b == 0 { // 创建异常的两种方式 err = fmt.Errorf("除数不能为0") err = errors.New("除数不能为0") } else { res = a / b } return res, err }
运行结果:
=== RUN TestThrowError 除数不能为0 --- PASS: TestThrowError (0.00s) PASS
异常处理终止程序
程序终止的方式:
- 系统自动终止
- 手动终止(企业级应用开发中不常用)格式 :panic("提示信息")
func TestExceptionPanic(t *testing.T) { /* 一种是程序发生异常时, 立刻退出终止程序继续运行 终止程序也分为两种: 1.系统自动终止 2.我们手动终止 (企业开发不常用) 格式: panic("提示信息") */ // 系统自动终止 //arr := [3]int{1, 3, 5} //for i := 0; i < 20; i++ { // fmt.Println(arr[i]) //} res := div1(10, 0) fmt.Println(res) } // 除法运算 func div1(a int, b int) (res int) { if b == 0 { //手动终止程序 panic("除数不能为0") } else { res = a / b } return res }
异常恢复
- 程序不要随意被终止,只要不是程序不能运行,需要建立让程序保持运行
- 如果程序出现 panic 异常,可以通过 defer 和 recover 实现 panic 异常的捕获,让程序正常运行。
注意
- defer 和 recover 必须要在 panic 之前被定义
- panic 异常会随着函数的调用栈向外传递 A函数调用了B函数, B函数调用了C函数,如果在C函数中抛出了一个panic异常, 那么这个异常会一层一层的传递到B和A,也就是在B和A函数中也能捕获到这个异常
func TestExceptionRecover(t *testing.T) { /* 1.程序不要随意被终止, 只要不是程序不能运行了, 就尽量让改程序继续保持运行 2.在Go语言中如果panic异常, 那么可以通过defer和recover来实现panic异常的捕获, 让程序继续执行 注意点: 1.defer和recover必须在panic抛出异常之前定义 2.panic异常会随着函数的调用栈向外传递 例如: A函数调用了B函数, B函数调用了C函数 如果在C函数中抛出了一个panic异常, 那么这个异常会一层一层的传递到B和A 也就是在B和A函数中也能捕获到这个异常 */ defer func() { if err := recover(); err != nil { fmt.Println("recover 捕获到了异常", err) } }() res := div2(10, 0) fmt.Println(res) } // 除法运算 func div2(a, b int) (res int) { // 在当前函数中捕获 //defer func() { // // defer无论所在的函数是正常结束,还是异常结束都会被执行 // // recover可以捕获panic异常 // if err := recover(); err != nil{ // fmt.Println("recover捕获到了", err) // } //}() if b == 0 { // 手动终止程序 panic("除数不能为0") } else { res = a / b } // 无效 //defer func() { // // defer无论所在的函数是正常结束,还是异常结束都会被执行 // // recover可以捕获panic异常 // if err := recover(); err != nil{ // fmt.Println(err) // } //}() return }
运行结果:
=== RUN TestExceptionRecover recover 捕获到了异常 除数不能为0 --- PASS: TestExceptionRecover (0.00s) PASS
捕获异常注意点
同一个函数中,多个 panic 异常,只要第一个会被捕获
func TestPanics(t *testing.T) { /* 捕获异常注意点: 1.同一个函数中, 多个panic异常, 只有第一个会被捕获 */ /*defer func() { if err := recover(); err != nil { fmt.Println(err) //异常1 } }() panic("异常1") panic("异常2") panic("异常3") panic("异常4")*/ panicfuc() } func panicfuc() { // 如果有异常写在defer中, 但是defer后面还有其它异常, 那么捕获到的是其它的异常 // 如果其它异常是写在defer前面, 那么和同一个函数中, 多个panic异常, 只有第一个会被捕获 defer func() { if err := recover(); err != nil { fmt.Println(err) // 异常B } }() defer func() { panic("异常B") }() panic("异常C") }
运行结果
=== RUN TestPanics 异常B --- PASS: TestPanics (0.00s) PASS