Closed mitchellh closed 4 years ago
I'm still reviewing and thinking through edge cases.
Here is a test case for one of them that might be worth including (the implementation already passes it):
https://github.com/felixge/go-multierror/commit/9b44b21f121fb1f033eded9b035d48a957e9df41
I'm still reviewing and thinking through edge cases.
Here is a test case for one of them that might be worth including (the implementation already passes it):
Cherry picked this commit and added the test. Thanks.
The primary mechanism that enables this functionality is making
Unwrap
on the top-level Error return a new "chain" structure that uses state to keep track of the current error.The chain implements errors.Is/As so that it compares to that current underlying error. And it implements Unwrap to move on to the next error.
A well-formed program using errors.Is/As/Unwrap exclusively will behave correctly with go-multierror in this case without dropping any errors. Direct comparisons such as
Unwrap() == myErr
will not work because we wrap in a chain. The user has to doerrors.Is(err, myErr)
which is the right thing to do anyways.When Unwrap is called on a top-level Error, we create a shallow copy of the errors so that you can continue using Error (modifying it, potentially in-place). There is a slight cost to this but it felt weird that calling Unwrap would share the same underlying data and cause potential data races. I think this is unlikely, but its also very unlikely the performance cost of the shallow copy of errors will matter either.