错误处理
Go采用返回错误值的方式(类似C),而不是像python,java那样以异常的方式进行处理。
if err != nil {
return nil, err
}
Go遵循大道至简的原则,避免了java那样try…catch 或者throw的异常处理方式,减少抛出一大堆异常的情况。
1. go中error类型
error是go的内置接口类型,只需要实现一个struct的Error()方法并返回一个字符串,就可以当作一个错误类型了。
type error interface {
Error() string
}
举一个除数为0的例子
import(
"errors"
"fmt"
)
func Divide(a, b int) (int, error) {
if b == 0 {
// errors.New() 返回一个error类型
return 0, errors.New("divide by zero")
}
return a / b, nil
}
func main() {
a, b := 1, 0
res, err := Divide(a, b)
if err != nil {
fmt.Println(err)
}
fmt.Println(res)
}
2. go自定义自己的业务异常
多数情况下,需要自定义自己的业务异常,比如一个博客系统中,1001码表示用户信息有误,2001码表示博客id不存在等等。
type Article struct {
Code int32
Message string
}
func (e *ArticleError)Error() string {
return fmt.Sprintf("[ArticleError] Code = %d, Message = %s", e.Code, e.Message)
}
func NewArticleError(code int32, message string) error {
return &Article {
Code: code,
Messgae: message,
}
}
3. Go异常处理panic/recover
3.1. defer
defer语句用来延迟一个函数(匿名函数)或方法的执行,它会在函数执行完成之后调用,一般为了防止代码里有资源泄露。对于打开资源比如文件,我们需要显式进行关闭,这种场合就是defer发挥作用的最好的场景,也是go代码中使用defer最常用的场景。
f, err := os.Open(file)
if err != nil {
return err
}
defer f.close()
// 防止忘记释放锁,也是defer常用的一个场景
mu.Lock()
defer mu.Unlock()
通常使用defer 和 recover组合来处理异常,可以实现java中类似try catch的功能。
3.2. panic/recover
go中一般使用的是error而不是panic,因为panic会导致代码退出。
func MustDivide(a, b int) int {
if b == 0 {
panic("divide by zero")
}
return a / b
}
如果不小心传入0,又不想让程序退出,go提供了一个recover函数用来从异常中恢复。
func Divide2(a, b int) (res int, err error) {
defer func(){
if e := recover();e != nil {
err = fmt.Errorf("%v", e)
}
}()
res = MustDivide(a, b)
return
}