From: Sean Liao Date: Wed, 22 Oct 2025 12:13:51 +0000 (+0100) Subject: errors: add examples for custom Is/As matching X-Git-Tag: go1.26rc1~202 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=1903782ade15293358c983e03db2bf238c5352fa;p=gostls13.git errors: add examples for custom Is/As matching Change-Id: Ia92dae13b6a4e9434b29d2ab3f698f6ba87b4b89 Reviewed-on: https://go-review.googlesource.com/c/go/+/713740 Reviewed-by: Damien Neil Reviewed-by: Mark Freeman LUCI-TryBot-Result: Go LUCI Auto-Submit: Damien Neil --- diff --git a/src/errors/example_test.go b/src/errors/example_test.go index 92ef36b101..298612c4ea 100644 --- a/src/errors/example_test.go +++ b/src/errors/example_test.go @@ -44,6 +44,39 @@ func ExampleNew() { // Output: emit macho dwarf: elf header corrupted } +func OopsNew() error { + return errors.New("an error") +} + +var ErrSentinel = errors.New("an error") + +func OopsSentinel() error { + return ErrSentinel +} + +// Each call to [errors.New] returns an unique instance of the error, +// even if the arguments are the same. To match against errors +// created by [errors.New], declare a sentinel error and reuse it. +func ExampleNew_unique() { + err1 := OopsNew() + err2 := OopsNew() + fmt.Println("Errors using distinct errors.New calls:") + fmt.Printf("Is(%q, %q) = %v\n", err1, err2, errors.Is(err1, err2)) + + err3 := OopsSentinel() + err4 := OopsSentinel() + fmt.Println() + fmt.Println("Errors using a sentinel error:") + fmt.Printf("Is(%q, %q) = %v\n", err3, err4, errors.Is(err3, err4)) + + // Output: + // Errors using distinct errors.New calls: + // Is("an error", "an error") = false + // + // Errors using a sentinel error: + // Is("an error", "an error") = true +} + // The fmt package's Errorf function lets us use the package's formatting // features to create descriptive error messages. func ExampleNew_errorf() { @@ -88,6 +121,29 @@ func ExampleIs() { // file does not exist } +type MyIsError struct { + err string +} + +func (e MyIsError) Error() string { + return e.err +} +func (e MyIsError) Is(err error) bool { + return err == fs.ErrPermission +} + +// Custom errors can implement a method "Is(error) bool" to match other error values, +// overriding the default matching of [errors.Is]. +func ExampleIs_custom_match() { + var err error = MyIsError{"an error"} + fmt.Println("Error equals fs.ErrPermission:", err == fs.ErrPermission) + fmt.Println("Error is fs.ErrPermission:", errors.Is(err, fs.ErrPermission)) + + // Output: + // Error equals fs.ErrPermission: false + // Error is fs.ErrPermission: true +} + func ExampleAs() { if _, err := os.Open("non-existing"); err != nil { var pathError *fs.PathError @@ -114,6 +170,63 @@ func ExampleAsType() { // Failed at path: non-existing } +type MyAsError struct { + err string +} + +func (e MyAsError) Error() string { + return e.err +} +func (e MyAsError) As(target any) bool { + pe, ok := target.(**fs.PathError) + if !ok { + return false + } + *pe = &fs.PathError{ + Op: "custom", + Path: "/", + Err: errors.New(e.err), + } + return true +} + +// Custom errors can implement a method "As(any) bool" to match against other error types, +// overriding the default matching of [errors.As]. +func ExampleAs_custom_match() { + var err error = MyAsError{"an error"} + fmt.Println("Error:", err) + fmt.Printf("TypeOf err: %T\n", err) + + var pathError *fs.PathError + ok := errors.As(err, &pathError) + fmt.Println("Error as fs.PathError:", ok) + fmt.Println("fs.PathError:", pathError) + + // Output: + // Error: an error + // TypeOf err: errors_test.MyAsError + // Error as fs.PathError: true + // fs.PathError: custom /: an error +} + +// Custom errors can implement a method "As(any) bool" to match against other error types, +// overriding the default matching of [errors.AsType]. +func ExampleAsType_custom_match() { + var err error = MyAsError{"an error"} + fmt.Println("Error:", err) + fmt.Printf("TypeOf err: %T\n", err) + + pathError, ok := errors.AsType[*fs.PathError](err) + fmt.Println("Error as fs.PathError:", ok) + fmt.Println("fs.PathError:", pathError) + + // Output: + // Error: an error + // TypeOf err: errors_test.MyAsError + // Error as fs.PathError: true + // fs.PathError: custom /: an error +} + func ExampleUnwrap() { err1 := errors.New("error1") err2 := fmt.Errorf("error2: [%w]", err1)