通过 errors.Unwrap 判断错误是否被包装:若返回 nil 则未被包装,否则为已包装;推荐使用 errors.Is 和 errors.As 安全遍历错误链并匹配特定错误。

在 Golang 中,
errors.Unwrap
函数用于逐层解开被包装的错误,这对于理解错误产生的上下文非常有帮助。它允许你访问原始错误,从而进行更精确的错误处理和诊断。
package mainimport ( "errors" "fmt")func operationA() error { return errors.New("operation A failed")}func operationB() error { err := operationA() if err != nil { return fmt.Errorf("operation B failed: %w", err) // %w 用于包装错误 } return nil}func operationC() error { err := operationB() if err != nil { return fmt.Errorf("operation C failed: %w", err) } return nil}func main() { err := operationC() if err != nil { fmt.Println("Original error:", err) // 解包错误 unwrappedErr := errors.Unwrap(err) fmt.Println("Unwrapped error (level 1):", unwrappedErr) // 进一步解包 if unwrappedErr != nil { unwrappedErr2 := errors.Unwrap(unwrappedErr) fmt.Println("Unwrapped error (level 2):", unwrappedErr2) } // 使用 errors.Is 判断错误类型 if errors.Is(err, errors.New("operation A failed")) { fmt.Println("Error is related to operation A") } }}
如何判断一个错误是否被包装过?
你可以使用
errors.Unwrap
函数来判断。如果
errors.Unwrap
返回
nil
,那么说明该错误没有被包装过。反之,如果返回一个非
nil
的错误,那么说明该错误是被包装过的。但是,更常见的做法是结合
errors.Is
和
errors.As
来判断错误类型和提取错误信息。
package mainimport ( "errors" "fmt")type CustomError struct { Message string}func (e *CustomError) Error() string { return e.Message}func operationD() error { return &CustomError{Message: "Custom error occurred"}}func operationE() error { err := operationD() if err != nil { return fmt.Errorf("operation E failed: %w", err) } return nil}func main() { err := operationE() if err != nil { // 使用 errors.As 提取自定义错误 var customErr *CustomError if errors.As(err, &customErr) { fmt.Println("Custom error message:", customErr.Message) } // 使用 errors.Is 判断是否为特定错误 if errors.Is(err, &CustomError{Message: "Custom error occurred"}) { fmt.Println("Error is a custom error") } }}
错误包装与错误链的区别是什么?
错误包装是指使用
fmt.Errorf
的
%w
动词将一个错误嵌入到另一个错误中,形成一个错误链。错误链就是由多个包装后的错误连接起来的结构。
errors.Unwrap
就是用于遍历这个链的。
package mainimport ( "errors" "fmt")func operationF() error { return errors.New("low-level error")}func operationG() error { err := operationF() if err != nil { return fmt.Errorf("operation G failed: %w", err) } return nil}func operationH() error { err := operationG() if err != nil { return fmt.Errorf("operation H failed: %w", err) } return nil}func main() { err := operationH() if err != nil { fmt.Println("Original error:", err) // 遍历错误链 currentErr := err for currentErr != nil { fmt.Println("Error in chain:", currentErr) currentErr = errors.Unwrap(currentErr) } }}
如何自定义错误类型并支持
errors.Unwrap
errors.Unwrap
?
要自定义错误类型并支持
errors.Unwrap
,你需要实现
Unwrap
方法。这个方法应该返回被包装的错误。
立即学习“go语言免费学习笔记(深入)”;
package mainimport ( "errors" "fmt")type MyError struct { Message string Err error // 被包装的错误}func (e *MyError) Error() string { return fmt.Sprintf("MyError: %s, caused by: %v", e.Message, e.Err)}func (e *MyError) Unwrap() error { return e.Err // 返回被包装的错误}func operationI() error { return errors.New("underlying error")}func operationJ() error { err := operationI() if err != nil { return &MyError{Message: "Operation J failed", Err: err} } return nil}func main() { err := operationJ() if err != nil { fmt.Println("Original error:", err) // 解包错误 unwrappedErr := errors.Unwrap(err) fmt.Println("Unwrapped error:", unwrappedErr) }}
使用
errors.Is
errors.Is
和
errors.As
的最佳实践是什么?
errors.Is
:用于判断错误链中是否存在特定类型的错误。它会递归地调用
Unwrap
方法来遍历错误链,直到找到匹配的错误或到达链的末尾。适用于判断是否为某个预定义的错误。
errors.As
:用于提取错误链中特定类型的错误,并将其赋值给一个变量。它也会递归地调用
Unwrap
方法,直到找到匹配的错误类型或到达链的末尾。适用于提取自定义错误类型中的信息。
最佳实践是优先使用
errors.Is
和
errors.As
,因为它们能够更安全、更可靠地处理错误链,避免直接比较错误字符串带来的问题。同时,保持错误类型的定义清晰,避免过度包装,使得错误链易于理解和调试。
以上就是如何在Golang中逐层解开被包装的错误(errors.Unwrap)的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1402543.html
微信扫一扫
支付宝扫一扫