Go最佳实践 - Error handling

背景

众所周知,Go的异常是很简单的,任何实现了error 接口的都可以作为异常。error接口定义如下:

type error interface {
    Error() string
}

错误检查

1.使用errorstructs和类型检查

异常处理一个比较好的实践是使用异常类型,你可以写一个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

你可能感兴趣的:(Go最佳实践 - Error handling)