Go's error handling functions, Is() and As(), claim to be recursive, enabling the unwrapping of multiple nested errors. However, it's unclear whether there exists a built-in type that implements the error interface and supports this recursive functionality without issue.
Flawed Custom Implementations
Attempts to create custom error types often encounter problems stemming from the fact that errors are compared by address in Go. A custom type that wraps errors as pointers results in unexpected behavior, such as the modified parent error affecting subsequent wraps.
A Workable Solution
A more robust solution involves creating a new error type, errorChain. This type contains an err field to store the current error and a next field to reference the next error in the chain. Additionally, it implements the Is() and As() methods to facilitate recursive error unwrapping.
Wrapping and Unwrapping
The Wrap() function takes multiple errors, creates an errorChain object, and links them together. The Unwrap() function traverses the chain, returning the next error in the sequence.
Example
Using the errorChain type, you can wrap and unwrap errors recursively:
type errorChain struct { err error next *errorChain } func Wrap(errs ...error) error { out := errorChain{err: errs[0]} n := &out for _, err := range errs[1:] { n.next = &errorChain{err: err} n = n.next } return out } func (c errorChain) Is(err error) bool { return c.err == err } func (c errorChain) As(target any) bool { return errors.As(c.err, target) }
Playground: https://go.dev/play/p/6BYGgIb728k
The above is the detailed content of Does Go's `Is()` and `As()` Truly Offer Recursive Error Unwrapping?. For more information, please follow other related articles on the PHP Chinese website!