错误处理和异常处理
错误处理使用error
go中没有结构化的异常处理,通过panic抛出,recover捕获
一、error和panic recover以及os.Exit区别 1.1.error error是一个内置的接口
1 2 3 4 5 type error interface { Error() string }
他只有一个Error方法,只要实现了Error,就是实现了error
1.2.panic和recover panic是一个内置函数接收一个interfact,recover是一个内置函数,返回一个interface
1 2 func panic (v interface {}) func recover () interface {}
panic用于不可恢复的错误
panic退出前会执行defer指定的内容
要注意不能随便recover,有可能是系统出错了,而在程序里面使用recover,只是记录了一下,没有做其他处理,可能会导致health check失效,形成僵尸服务进程
对于不确定性的错误,比较好的方式是直接让我们的程序crash,让其托管的守护进程(比如systemd)帮他重启。
1.3.os.Exit
os.Exit
退出的时候,不会调用defer指定的函数
os.Exit
退出时,不会输出当前调用栈信息
二、错误处理 2.1.简单使用
1 2 3 4 5 6 7 8 func main () { conent, err:=ioutil.ReadFile("filepath" ) if err !=nil { }else { fmt.Println(string (conent)) } }
2.2.自定义error 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 type fileError struct { errString string }func (fe *fileError) Error() string { return fe.errString }func openFile () ([]byte , error ) { return nil , &fileError{"文件打开错误" } }func main () { conent, err := openFile() if err != nil { fmt.Println(err) } else { fmt.Println(string (conent)) } }
2.3.函数错误处理策略
将错误继续传递下去
内部出现错误,可以进行重试,如果多次重试无果,再返回错误;例如设置一个HTTP请求的timeout重试n次
如果重试不能解决,应该返回错误信息,然后调用者进行处理
有些时候,可以忽略错误,记录一下,继续执行
有些时候,直接忽略处理,继续执行,这种情况比较少。(比如创建一个目录前判断目录有没有存在)
三、宕机和恢复 panic是程序异常(宕机)了,recover则可以用来将程序从panic中恢复继续执行
3.1.简单使用
recover只能捕获上一个panic
defer调用中引发的panic,可被后续defer调用捕获,仅最后一个错误可被捕获
多个panic 要多个recover去捕获, recover写在panic前面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 func test1 () { defer func () { if err := recover (); err != nil { fmt.Println(err) } }() defer func () { panic ("panic in test defer 1" ) }() defer func () { panic ("panic in test defer 2" ) }() defer func () { if err := recover (); err != nil { fmt.Println(err) } }() panic ("panic in test" ) }func main () { defer func () { if err := recover (); err != nil { fmt.Println(err) } }() test1() println ("before panic in main" ) panic ("panic in main" ) }
直接在defer中调用recover才能捕获到panic
1 2 3 4 5 6 7 8 9 10 11 12 13 func test2 () { defer func () { fmt.Println("defer函数中直接调用recover才能捕获到" , recover ()) }() defer fmt.Println("defer直接调用fmt.Println,recover捕获不到,返回nil" , recover ()) defer func () { func () { fmt.Println("defer函数中的函数执行recover,捕获不到,返回nil" , recover ()) }() }() panic ("test panic" ) }
Refs