背景
众所周知,Go的异常是很简单的,任何实现了error
接口的都可以作为异常。error
接口定义如下:
type error interface {
Error() string
}
错误检查
1.使用error
structs和类型检查
异常处理一个比较好的实践是使用异常类型,你可以写一个struct实现error
接口,然后使用switch
区分不同类型。一个除数为0的异常的小例子。
定义一种异常类型ErrZeroDivision
,实现error
接口的Error() string
方法。
type ErrZeroDivision struct {
message string
}
func NewErrZeroDivision(message string) *ErrZeroDivision {
return &ErrZeroDivision{
message: message,
}
}
func (e *ErrZeroDivision) Error() string {
return e.message
}
这个异常可以这样使用
func main() {
result, err := divide(1.0, 0.0)
if err != nil {
switch err.(type) {
case *ErrZeroDivision:
fmt.Println(err.Error())
default:
fmt.Println("咩咩咩咩?")
}
}
fmt.Println(result)
}
func divide(a, b float64) (float64, error) {
if b == 0.0 {
return 0.0, NewErrZeroDivision("除数不能为0")
}
return a / b, nil
}
注意switch err.(type)
这一行代码,通过switch区分不同的错误类型
2.使用errors
包直接比较
上面提到的错误处理的方法可以用errors
包处理异常来代替,这个方法适合快速error检查
var errNotFound = errors.New("此项未找到")
func main() {
err := getItem(123) // getItem方法会抛出 errNotFound异常
if err != nil {
switch err {
case errNotFound:
log.Println("请求项不存在")
default:
log.Println("未知错误")
}
}
}
这个方法不适合复杂的异常处理,需要处理复杂的异常,参考1的方法
即时错误处理
有时候会遇到这样的代码
func example1() error {
err := call1()
return err
}
此方法没有立即处理异常,假如某人在err := call1()
和return err
之间加了一些代码,可能会遮盖第一个error,导致你不知道到底是哪一行抛的异常。两种方式可以解决:
// 折叠return和call1()
func example2() error {
return call1()
}
// 调用call1()后立即进行错误处理
func example3() error {
err := call1()
if err != nil {
return err
}
return nil
}
translate from https://medium.com/@sebdah/go-best-practices-error-handling-2d15e1f0c5ee