@@ -2,6 +2,7 @@ package errors
22
33import (
44 "errors"
5+ "reflect"
56)
67
78// Import all the standard errors functions as a convenience.
@@ -29,3 +30,54 @@ func New(text string) error {
2930func Unwrap (err error ) error {
3031 return errors .Unwrap (err )
3132}
33+
34+ // Last finds the last error in err's chain that matches target, and if one is found, sets
35+ // target to that error value and returns true. Otherwise, it returns false.
36+ //
37+ // The chain consists of err itself followed by the sequence of errors obtained by
38+ // repeatedly calling Unwrap.
39+ //
40+ // An error matches target if the error's concrete value is assignable to the value
41+ // pointed to by target, or if the error has a method `As(any) bool` such that
42+ // As(target) returns true.
43+ //
44+ // An error type might provide an As() method so it can be treated as if it were a
45+ // different error type.
46+ //
47+ // Last panics if target is not a non-nil pointer to either a type that implements
48+ // error, or to any interface type.
49+ //
50+ // NOTE: Last() is much slower than As(). Therefore As() should always be used
51+ // unless you absolutely need Last() to retrieve the last error in the error chain
52+ // that matches the target.
53+ func Last (err error , target any ) bool {
54+ if target == nil {
55+ panic ("errors: target cannot be nil" )
56+ }
57+ val := reflect .ValueOf (target )
58+ typ := val .Type ()
59+ if typ .Kind () != reflect .Ptr || val .IsNil () {
60+ panic ("errors: target must be a non-nil pointer" )
61+ }
62+ targetType := typ .Elem ()
63+ if targetType .Kind () != reflect .Interface && ! targetType .Implements (errorType ) {
64+ panic ("errors: *target must be interface or implement error" )
65+ }
66+ var found error
67+ for err != nil {
68+ if reflect .TypeOf (err ).AssignableTo (targetType ) {
69+ found = err
70+ }
71+ if x , ok := err .(interface { As (any ) bool }); ok && x .As (target ) {
72+ found = err
73+ }
74+ err = Unwrap (err )
75+ }
76+ if found != nil {
77+ val .Elem ().Set (reflect .ValueOf (found ))
78+ return true
79+ }
80+ return false
81+ }
82+
83+ var errorType = reflect .TypeOf ((* error )(nil )).Elem ()
0 commit comments