如何拆分包装错误以获取其各个组成部分?
如何拆分包装错误以获取其各个组成部分?
我完全懂你的困扰——用标准库的fmt.Errorf("%w", err)包装多层错误后,想要把每一层拆出来单独处理,但errors.Unwrap()每次只能返回下一层错误,没法直接拿到所有组成部分;而且那个第三方错误库已经归档了,总不能为了拆错误就把项目里所有的包装方式都换成他们的写法,实在太折腾了。
其实我们完全可以基于Go标准库的工具,自己写个简单的函数来解决这个问题,不用依赖任何第三方包,也不用改你原来的错误包装逻辑。
方案1:获取所有包装的错误切片
我们可以写一个循环遍历的函数,把每一层错误都收集到切片里:
package main import ( "errors" "fmt" ) // UnwrapAll 遍历所有包装层级,返回包含每一层错误的切片(从最外层到最内层) func UnwrapAll(err error) []error { var errs []error for currentErr := err; currentErr != nil; currentErr = errors.Unwrap(currentErr) { errs = append(errs, currentErr) } return errs } func main() { // 模拟多层包装的错误场景 baseErr := errors.New("原始错误:数据库连接超时") wrapped1 := fmt.Errorf("包装层1:无法初始化数据存储: %w", baseErr) wrapped2 := fmt.Errorf("包装层2:用户服务启动失败: %w", wrapped1) // 拆分所有错误 allErrors := UnwrapAll(wrapped2) for idx, e := range allErrors { fmt.Printf("第%d层错误:%v\n", idx+1, e) } }
运行这个代码,你会得到从最外层到最内层的所有错误:
第1层错误:用户服务启动失败: 无法初始化数据存储: 原始错误:数据库连接超时 第2层错误:无法初始化数据存储: 原始错误:数据库连接超时 第3层错误:原始错误:数据库连接超时
如果你想拿到从内层到外层的顺序,只需要在收集的时候把新错误插在切片开头就行:
errs = append([]error{currentErr}, errs...)
方案2:单独获取每次Unwrap时被移除的错误
如果你只是想拿到调用errors.Unwrap()时被“拿掉”的那一层(也就是当前的错误实例),其实每次调用Unwrap()前的err就是你要的那个。比如:
currentErr := wrapped2 // 被Unwrap移除的就是currentErr本身 nextErr := errors.Unwrap(currentErr)
要是你想逐个处理每一层,直接用循环就行,和上面的UnwrapAll逻辑类似,只是不用收集成切片,而是处理当前层后再走到下一层。
另外,如果你需要的是类似第三方库Cause()的效果(拿到最内层的原始错误),用UnwrapAll返回的切片最后一个元素就可以了:
allErrors := UnwrapAll(wrapped2) rootErr := allErrors[len(allErrors)-1]
这个方案完全基于标准库,完美适配你用fmt.Errorf包装错误的习惯,不用做任何代码迁移,非常省心。
备注:内容来源于stack exchange,提问作者bonculars
相关产品推荐
相关产品推荐

