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。