]> Cypherpunks repositories - gostls13.git/commitdiff
errors: add examples for custom Is/As matching
authorSean Liao <sean@liao.dev>
Wed, 22 Oct 2025 12:13:51 +0000 (13:13 +0100)
committerGopher Robot <gobot@golang.org>
Fri, 21 Nov 2025 20:40:11 +0000 (12:40 -0800)
Change-Id: Ia92dae13b6a4e9434b29d2ab3f698f6ba87b4b89
Reviewed-on: https://go-review.googlesource.com/c/go/+/713740
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Mark Freeman <markfreeman@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Damien Neil <dneil@google.com>

src/errors/example_test.go

index 92ef36b1010edbc6d4c66e7e5a050e2a06fc10b1..298612c4eac92c3827c8f70ab68df93d48f79941 100644 (file)
@@ -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)