Go Errors: Is() and As() Support Recursive Error Wrapping
In Go, error handling is crucial for managing and analyzing errors throughout the application. The error interface provides a common way to represent errors, and it includes methods like Is() and As() for error introspection.
However, it's important to note that the standard error interface does not support recursive error wrapping. This means that if you use fmt.Errorf to wrap errors, you won't be able to use Is() and As() to check for underlying errors recursively.
Custom Error Type for Recursive Error Wrapping
To achieve recursive error wrapping, you can create a custom error type that implements the error interface. This type should include a reference to the wrapped error and define custom Is() and As() methods to enable recursive comparisons.
Here's an example implementation of a recursive error type:
type errorChain struct { err error next *errorChain } func (c errorChain) Is(err error) bool { // Check the current error against the given error if c.err == err { return true } // Check if there is a wrapped error and recursively call Is() if c.next != nil { return c.next.Is(err) } return false } func (c errorChain) As(target interface{}) bool { // Check if the current error As() to the target interface if errors.As(c.err, target) { return true } // Check if there is a wrapped error and recursively call As() if c.next != nil { return c.next.As(target) } return false }
Wrapping Errors Recursively
Once you have defined a custom error type, you can wrap errors recursively using a function like the following:
func Wrap(errs ...error) error { if len(errs) == 0 { return nil } // Create the first error in the chain out := &errorChain{err: errs[0]} // Iterate over the remaining errors for _, err := range errs[1:] { // Link the errors together out.next = &errorChain{err: err} out = out.next } return out }
Usage
You can now use this custom error type to wrap errors and check for underlying errors recursively using Is() and As(). For example:
var Err1 = errors.New("error 1") var Err2 = errors.New("error 2") var Err3 = errors.New("error 3") err := Wrap(Err1, Err2, Err3) fmt.Println(errors.Is(err, Err2)) // true fmt.Println(errors.Is(err, Err3)) // true fmt.Println(errors.Is(err, Err0)) // false
Conclusion
By creating a custom error type with recursive Is() and As() methods, you can achieve recursive error wrapping and perform more precise error handling in your Go applications.
The above is the detailed content of How Can I Achieve Recursive Error Wrapping with Is() and As() in Go?. For more information, please follow other related articles on the PHP Chinese website!