异常处理
- 概念
不按我们预期执行的都可以称为异常
1. 一种是程序发生异常时,将异常信息反馈给使用者
- 创建异常信息有两种方法
- 创建方式1
fmt.Errorf(" 提示的内容 ")
- 创建方式2
errors.New("提示的内容")
- 案例
package main
import (
"errors"
"fmt"
)
func main() {
if res1,err := division(20,5); err==nil{
fmt.Println("res1 = ",res1) // res1 = 4
}else {
fmt.Println("err = ",err)
}
if res2,err := division(10,0);err==nil {
fmt.Println(res2)
}else {
fmt.Println(err) //除法运算除数不能为0
}
}
// 除法运算的函数 运算规则: 除数不能为0
func division(a,b int)(res int,err error){
if b==0 {
//创建错误提示给用户
err = fmt.Errorf("除法运算除数不能为0")
err = errors.New("除法运算除数不能为0")
}else{
res = a/b
}
return
}
-
注意点
本质上两个方法底层实现原理都是一样
//package builtin中定义了一个接口
type Error interface {
Error() string
}
//package errors 定义了一个结构体
type errorsString struct {
s string
}
// errorsString结构体实现了builtin中的接口
func (e *errorsString) Error() string{
return e.s
}
// 这个函数是errors 包里面的 所以调用的时候是 errors.New()
func New(text string)Error{
return &errorsString{text}
}
2. 一种是程序发生异常时,立刻退出终止程序 继续运行
- 终止程序分为两种
- 系统自动终止程序
- 案例
package main
import "fmt"
func main() {
arr :=[4]int{1,3,5,7}
for i:=0;i<10;i++{
fmt.Println(arr[i])
}
/* 系统打印
1
3
5
7
panic: runtime error: index out of range
goroutine 1 [running]:
main.main()
*/
}
- 手动终止程序(企业开发不常用)
- 格式
panic( "提示的内容" )
package main
import "fmt"
func main() {
res := division(10,5)
fmt.Println(res) // res = 2
res2 := division(10,0)
fmt.Println(res2)
/**
panic: 除数不能为零
*/
}
// 定义除法运算的函数
func division(a,b int)(res int){
if b==0 {
// 手动终止
panic("除数不能为零")
}else {
res = a/b
}
return
}
异常恢复
-
宗旨 程序不要随意被终止,只要不是程序不能运行, 就尽量让程序运行下去
-
在Go语言中如果出现了panic异常,可以通过 defer和recover 来实现panic异常的捕获,让程序继续运行
-
格式
defer func() {
if err := recover(); err!= nil {
fmt.Println("recover捕获到",err)
}
}()
- 注意点
- defer 和 recover 必须在panic 抛出异常之前定义
defer无论所在函数是正常结束还是异常结束都会被执行
- panic异常会随着函数的调用向栈外传递
例如: A函数调用了B函数,B函数调用了C函数, C函数抛出了异常panic, 那么这个异常会 一层一层传递到B函数和A函数,也就是说在B函数和A函数中也能捕获异常
package main
import "fmt"
func main() {
division(10,0) // recover捕获到 除数不能为零
}
// 定义除法运算的函数
func division(a,b int)(res int){
// defer 必须定义在 panic 抛出异常异常之前
defer func() {
if err := recover(); err!=nil{
fmt.Println("recover捕获到",err)
}
}()
if b==0 {
// 手动终止
panic("除数不能为零")
}else {
res = a/b
}
return
}
异常恢复其他注意点
- 同一个函数中如果有多个异常 那么只有第一个异常会被捕获
- 案例
package main
import "fmt"
func main() {
defer func() {
if err := recover(); err!=nil {
fmt.Println("recover 捕获到",err) // recover 捕获到 异常A
}
}()
panic("异常A")
panic("异常B")
panic("异常C")
}
- 如果defer中也有终止异常的话,且defer前面也有终止异常的话 , 那么recover 只会捕获defer前面的
- 案例
package main
import "fmt"
func main() {
defer func() {
if err := recover(); err!=nil {
fmt.Println("recover 捕获到",err) // recover 捕获到 defer前的异常
}
}()
panic("defer前的异常")
defer func() {
panic("defer中的异常")
}()
}
- 如果defer中也有异常, 且defer后也有异常抛出, 那么只会捕获defer中的异常
- 案例
package main
import "fmt"
func main() {
defer func() {
if err := recover(); err!=nil {
fmt.Println("recover 捕获到",err) // recover 捕获到 defer中的异常
}
}()
defer func() {
panic("defer中的异常")
}()
panic("defer后的异常")
}
网友评论