Go1.13 Error新特征
即将发布的Go1.13对errors
包进行了增强,新特征主要来自提案:
Proposal: Go 2 Error Inspection
。
为了使error
为程序员和程序提供足够多的相关信息,Go1.13对error
处理的更新如下:
- 定义
Wrapper
接口(其实更应该称为Unwrapper
) [1] ,用于Unwrap操作。 errors
包新增了func Is(err, target error) bool
和func As(err error, target interface{}) bool
函数,用于比较和断言error。- 定义了
func Unwrap(err error) error
用于快速Unwrap错误。 fmt
包的Errorf
方法修改了实现,增加新的verb%w
,%w
只接受error类型的参数,用于快速Wrap错误。
包装错误
err := errors.New("my error")
err = fmt.Errorf("1s wrapping my error with Errorf: %w", err)
err = fmt.Errorf("2nd wrapping my error with Errorf: %w", err)
错误的解包
err = errors.Unwrap(err)
func Unwrap(err error) error
间接调用err的Unwrap() error
方法。
错误比较
if errors.Is(err,os.PathError) {
//Do Something
}
Is
函数会逐层调用Unwrap
函数并比较error链上的所有error
是否与target
匹配,直到匹配targer
或者Unwrap
返回nil
。匹配target
的条件:Unwrap
返回值与target
相同(==)或者Unwrap
的返回值实现了Is(error) bool
方法,调用Is(target)
返回true
。
错误断言
if errors.As(err,&target){
//Do Something
}
As
函数会逐层调用Unwrap
函数并比较error链上的所有error
是否与target
匹配,如果匹配,则把匹配到的值设置到target
并回返true
。
如果target
不是指向error
类型或者interface{}
类型的指针,则会panic
,如果err
为nil
,返回false
示例
package main
import (
"errors"
"fmt"
)
//BaseError is a Custom error
type BaseError struct {
msg string
}
func (b BaseError) Error() string {
return fmt.Sprintf("BaseError Message : %s", b.msg)
}
var baseError = BaseError{msg: "Base"}
func main() {
err := fmt.Errorf("Wrap 001 : %w", baseError)
err = fmt.Errorf("Wrap 002 : %w", err)
fmt.Println(err)
err = errors.Unwrap(err)
fmt.Println(err)
if errors.Is(err, baseError) {
fmt.Println("err Is baseError")
}
var anotherError BaseError
if errors.As(err, &anotherError) {
fmt.Printf("%v\n", anotherError)
}
}
执行结果:
$ go run main.go
Wrap 002 : Wrap 001 : BaseError Message : Base
Wrap 001 : BaseError Message : Base
err Is baseError
BaseError Message : Base
建议
仅包装来自公共函数或方法的错误。否则就直接传播错误。
参考链接
[1] : 写这篇文章时,Go1.13版本还没有正式release,github仓库RC1分支的代码中没有Wrapper
接口的定义,只是在Unwrap
方法中引用了匿名的interface
参见
。
之所以称之为Wrapper
接口是因为
https://github.com/golang/xerrors/blob/master/wrap.go#L12
中定义的接口是Wrapper
。