From 754fe7884373465bd33352d29e5186559335c1fb Mon Sep 17 00:00:00 2001 From: junler Date: Fri, 7 Jun 2024 16:36:23 +0800 Subject: [PATCH 1/3] Compatibility standard library error: IIs interface not implemented --- errors/gerror/gerror_api_stack.go | 10 +++++++--- errors/gerror/gerror_z_unit_test.go | 9 +++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/errors/gerror/gerror_api_stack.go b/errors/gerror/gerror_api_stack.go index 79b4d6b02af..1737c265cff 100644 --- a/errors/gerror/gerror_api_stack.go +++ b/errors/gerror/gerror_api_stack.go @@ -93,10 +93,14 @@ func Equal(err, target error) bool { // Is reports whether current error `err` has error `target` in its chaining errors. // It is just for implements for stdlib errors.Is from Go version 1.17. func Is(err, target error) bool { - if e, ok := err.(IIs); ok { - return e.Is(target) + if err == nil { + return err == target } - return false + e, ok := err.(IIs) + if !ok { + e = Wrap(err, "").(IIs) + } + return e.Is(target) } // HasError is alias of Is, which more easily understanding semantics. diff --git a/errors/gerror/gerror_z_unit_test.go b/errors/gerror/gerror_z_unit_test.go index cb892c401fc..226d347cad0 100644 --- a/errors/gerror/gerror_z_unit_test.go +++ b/errors/gerror/gerror_z_unit_test.go @@ -414,10 +414,15 @@ func Test_Is(t *testing.T) { err2 := gerror.Wrap(err1, "2") err2 = gerror.Wrap(err2, "3") t.Assert(gerror.Is(err2, err1), true) + + ErrNotFound := errors.New("not found") + t.Assert(gerror.Is(ErrNotFound, ErrNotFound), true) + t.Assert(gerror.Is(nil, ErrNotFound), false) + t.Assert(gerror.Is(nil, nil), true) }) } -func Test_HashError(t *testing.T) { +func Test_HasError(t *testing.T) { gtest.C(t, func(t *gtest.T) { err1 := errors.New("1") err2 := gerror.Wrap(err1, "2") @@ -426,7 +431,7 @@ func Test_HashError(t *testing.T) { }) } -func Test_HashCode(t *testing.T) { +func Test_HasCode(t *testing.T) { gtest.C(t, func(t *gtest.T) { t.Assert(gerror.HasCode(nil, gcode.CodeNotAuthorized), false) err1 := errors.New("1") From b48f8c598fb53771255a49764640a0ed4b5b9b6c Mon Sep 17 00:00:00 2001 From: junler Date: Fri, 7 Jun 2024 17:17:58 +0800 Subject: [PATCH 2/3] Support comparison between standard library errors --- errors/gerror/gerror_z_example_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/errors/gerror/gerror_z_example_test.go b/errors/gerror/gerror_z_example_test.go index 998b5423700..6d828abbde5 100644 --- a/errors/gerror/gerror_z_example_test.go +++ b/errors/gerror/gerror_z_example_test.go @@ -77,7 +77,7 @@ func ExampleIs() { fmt.Println(gerror.Is(err1, err2)) // Output: - // false + // true // true // true // false From 0855827a5ec4c1057eb5eed6dfddfc3bfc5c438f Mon Sep 17 00:00:00 2001 From: John Guo Date: Wed, 12 Jun 2024 21:14:18 +0800 Subject: [PATCH 3/3] fix #3633 --- errors/gerror/gerror.go | 6 ------ errors/gerror/gerror_api_stack.go | 19 ++++++++----------- errors/gerror/gerror_error.go | 19 ------------------- errors/gerror/gerror_z_unit_test.go | 19 ++++++++++++++++--- 4 files changed, 24 insertions(+), 39 deletions(-) diff --git a/errors/gerror/gerror.go b/errors/gerror/gerror.go index 8155331a5cd..e252d872a13 100644 --- a/errors/gerror/gerror.go +++ b/errors/gerror/gerror.go @@ -15,12 +15,6 @@ import ( "github.com/gogf/gf/v2/errors/gcode" ) -// IIs is the interface for Is feature. -type IIs interface { - Error() string - Is(target error) bool -} - // IEqual is the interface for Equal feature. type IEqual interface { Error() string diff --git a/errors/gerror/gerror_api_stack.go b/errors/gerror/gerror_api_stack.go index 1737c265cff..b8c5f269c90 100644 --- a/errors/gerror/gerror_api_stack.go +++ b/errors/gerror/gerror_api_stack.go @@ -7,6 +7,7 @@ package gerror import ( + "errors" "runtime" ) @@ -91,21 +92,17 @@ func Equal(err, target error) bool { } // Is reports whether current error `err` has error `target` in its chaining errors. -// It is just for implements for stdlib errors.Is from Go version 1.17. +// There's similar function HasError which is designed and implemented early before errors.Is of go stdlib. +// It is now alias of errors.Is of go stdlib, to guarantee the same performance as go stdlib. func Is(err, target error) bool { - if err == nil { - return err == target - } - e, ok := err.(IIs) - if !ok { - e = Wrap(err, "").(IIs) - } - return e.Is(target) + return errors.Is(err, target) } -// HasError is alias of Is, which more easily understanding semantics. +// HasError performs as Is. +// This function is designed and implemented early before errors.Is of go stdlib. +// Deprecated: use Is instead. func HasError(err, target error) bool { - return Is(err, target) + return errors.Is(err, target) } // callers returns the stack callers. diff --git a/errors/gerror/gerror_error.go b/errors/gerror/gerror_error.go index b05bfd1f5e1..4824f9bb244 100644 --- a/errors/gerror/gerror_error.go +++ b/errors/gerror/gerror_error.go @@ -125,22 +125,3 @@ func (err *Error) Equal(target error) bool { } return true } - -// Is reports whether current error `err` has error `target` in its chaining errors. -// It is just for implements for stdlib errors.Is from Go version 1.17. -func (err *Error) Is(target error) bool { - if Equal(err, target) { - return true - } - nextErr := err.Unwrap() - if nextErr == nil { - return false - } - if Equal(nextErr, target) { - return true - } - if e, ok := nextErr.(IIs); ok { - return e.Is(target) - } - return false -} diff --git a/errors/gerror/gerror_z_unit_test.go b/errors/gerror/gerror_z_unit_test.go index 226d347cad0..29da031372b 100644 --- a/errors/gerror/gerror_z_unit_test.go +++ b/errors/gerror/gerror_z_unit_test.go @@ -415,10 +415,23 @@ func Test_Is(t *testing.T) { err2 = gerror.Wrap(err2, "3") t.Assert(gerror.Is(err2, err1), true) - ErrNotFound := errors.New("not found") - t.Assert(gerror.Is(ErrNotFound, ErrNotFound), true) - t.Assert(gerror.Is(nil, ErrNotFound), false) + var ( + errNotFound = errors.New("not found") + gerror1 = gerror.Wrap(errNotFound, "wrapped") + gerror2 = gerror.New("not found") + ) + t.Assert(errors.Is(errNotFound, errNotFound), true) + t.Assert(errors.Is(nil, errNotFound), false) + t.Assert(errors.Is(nil, nil), true) + + t.Assert(gerror.Is(errNotFound, errNotFound), true) + t.Assert(gerror.Is(nil, errNotFound), false) t.Assert(gerror.Is(nil, nil), true) + + t.Assert(errors.Is(gerror1, errNotFound), true) + t.Assert(errors.Is(gerror2, errNotFound), false) + t.Assert(gerror.Is(gerror1, errNotFound), true) + t.Assert(gerror.Is(gerror2, errNotFound), false) }) }