Go 的错误处理和其他主流的编程语言如 Java、C# 等不同:
Go 中的错误类型实现为如下接口:
- type error interface {
- Error() string
- }
- 复制代码
所以,Go 的错误类型就这么简单,只要是任何实现 Error() 方法的东西,返回信息是字符串类型即可。
那么,我们可以轻松自定义错误,可以通过两种方式构建错误:
1、Go 的内置错误 errors
2、 fmt 包即时构建错误,将错误信息输出
实现 Demo 如下
自定义错误机制
- package main
-
- func customErr() error {
- return errors.New("server not work")
- }
-
- func customErr2() error {
- host := "http://localhost:2033"
- fmt.Errorf("server %s set up fail", host)
- }
- 复制代码
所以,在处理错误时通过判断 err 参数来处理错误:
- result, err := doHandler()
- if err != nil {
- // handle error
- }
- 复制代码
当处理比较多业务逻辑时,可能调用很多方法,这时就会处理一大堆的 err,如下所示:
- func doHandler(){
- res, err := getA()
- if err!=nil {
- // handle getA error
- }
- err := getB()
- if err!=nil {
- // handle getB error
- }
- err := getc()
- if err!=nil {
- // handle getc error
- }
- }
- 复制代码
每个方法都需要判断 error 。可能会觉得上述代码不够优雅且浪费代码,但这就是 Go 的代码。
Go 中对预期内的错误,定义相对的错误处理,这样方便在代码的其他部分显式的检查他们,遇到这种错误只需要执行不同的代码分支即可。
- var (
- NotFoundError = errors.New("未找到参数")
- ForbiddenError = errors.New("权限不足")
- )
-
-
- func doHandler(){
- if userId == ''{
- return NotFoundError
- }
- }
- 复制代码
预定义错误,只能处理自己定义该类型的错误场景。且在使用时,必须通过和预期的值进行比较判断。这种关联性太强,局限性太大。
返回错误时,可能需要携带额外的错误字段或者其他的错误信息,而不是单独的返回错误字符串。通过自定义错误类型,可以让我们错误信息包含更多的信息。
- type CustomError struct {
- UserId string
- Message string
- }
-
- func (e * CustomError) Error() string{
- return fmt.Sprintf("%s : %s", e.UserId, e.Msg)
- }
- 复制代码
CustomError 实现了 Error 接口,我们可以使用 error.As 或者使用类型断言(err.(type)) 来检查标准错误并将其转换为更具体的错误。
和预定义错误相比,自定义错误能够包装底层错误以提供更多的上下文,但是同样会将错误类型暴露出去。
前面2种会暴露错误类型给外部,所以可以将通过提供给不公开的接口,仅暴露具体的错误方法,
- type serverError interface {
- default() bool
- }
- func NotFoundError(err error) bool {
- m,ok := err.(serverError)
- return ok && m.default()
- }
- 复制代码
以上只提供具体错误方法,返回错误,暴露错误判定接口,不返回类型。通过断言错误实现特定的行为,而不是断言错误是特定的类型或值。这种错误处理方式相对于灵活。
作者:六号积极分子
链接:https://juejin.cn/post/7123843734717857828
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。