Skip to content

Commit 1903782

Browse files
seankhliaogopherbot
authored andcommitted
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 <[email protected]> Reviewed-by: Mark Freeman <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Damien Neil <[email protected]>
1 parent ec92bc6 commit 1903782

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

src/errors/example_test.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,39 @@ func ExampleNew() {
4444
// Output: emit macho dwarf: elf header corrupted
4545
}
4646

47+
func OopsNew() error {
48+
return errors.New("an error")
49+
}
50+
51+
var ErrSentinel = errors.New("an error")
52+
53+
func OopsSentinel() error {
54+
return ErrSentinel
55+
}
56+
57+
// Each call to [errors.New] returns an unique instance of the error,
58+
// even if the arguments are the same. To match against errors
59+
// created by [errors.New], declare a sentinel error and reuse it.
60+
func ExampleNew_unique() {
61+
err1 := OopsNew()
62+
err2 := OopsNew()
63+
fmt.Println("Errors using distinct errors.New calls:")
64+
fmt.Printf("Is(%q, %q) = %v\n", err1, err2, errors.Is(err1, err2))
65+
66+
err3 := OopsSentinel()
67+
err4 := OopsSentinel()
68+
fmt.Println()
69+
fmt.Println("Errors using a sentinel error:")
70+
fmt.Printf("Is(%q, %q) = %v\n", err3, err4, errors.Is(err3, err4))
71+
72+
// Output:
73+
// Errors using distinct errors.New calls:
74+
// Is("an error", "an error") = false
75+
//
76+
// Errors using a sentinel error:
77+
// Is("an error", "an error") = true
78+
}
79+
4780
// The fmt package's Errorf function lets us use the package's formatting
4881
// features to create descriptive error messages.
4982
func ExampleNew_errorf() {
@@ -88,6 +121,29 @@ func ExampleIs() {
88121
// file does not exist
89122
}
90123

124+
type MyIsError struct {
125+
err string
126+
}
127+
128+
func (e MyIsError) Error() string {
129+
return e.err
130+
}
131+
func (e MyIsError) Is(err error) bool {
132+
return err == fs.ErrPermission
133+
}
134+
135+
// Custom errors can implement a method "Is(error) bool" to match other error values,
136+
// overriding the default matching of [errors.Is].
137+
func ExampleIs_custom_match() {
138+
var err error = MyIsError{"an error"}
139+
fmt.Println("Error equals fs.ErrPermission:", err == fs.ErrPermission)
140+
fmt.Println("Error is fs.ErrPermission:", errors.Is(err, fs.ErrPermission))
141+
142+
// Output:
143+
// Error equals fs.ErrPermission: false
144+
// Error is fs.ErrPermission: true
145+
}
146+
91147
func ExampleAs() {
92148
if _, err := os.Open("non-existing"); err != nil {
93149
var pathError *fs.PathError
@@ -114,6 +170,63 @@ func ExampleAsType() {
114170
// Failed at path: non-existing
115171
}
116172

173+
type MyAsError struct {
174+
err string
175+
}
176+
177+
func (e MyAsError) Error() string {
178+
return e.err
179+
}
180+
func (e MyAsError) As(target any) bool {
181+
pe, ok := target.(**fs.PathError)
182+
if !ok {
183+
return false
184+
}
185+
*pe = &fs.PathError{
186+
Op: "custom",
187+
Path: "/",
188+
Err: errors.New(e.err),
189+
}
190+
return true
191+
}
192+
193+
// Custom errors can implement a method "As(any) bool" to match against other error types,
194+
// overriding the default matching of [errors.As].
195+
func ExampleAs_custom_match() {
196+
var err error = MyAsError{"an error"}
197+
fmt.Println("Error:", err)
198+
fmt.Printf("TypeOf err: %T\n", err)
199+
200+
var pathError *fs.PathError
201+
ok := errors.As(err, &pathError)
202+
fmt.Println("Error as fs.PathError:", ok)
203+
fmt.Println("fs.PathError:", pathError)
204+
205+
// Output:
206+
// Error: an error
207+
// TypeOf err: errors_test.MyAsError
208+
// Error as fs.PathError: true
209+
// fs.PathError: custom /: an error
210+
}
211+
212+
// Custom errors can implement a method "As(any) bool" to match against other error types,
213+
// overriding the default matching of [errors.AsType].
214+
func ExampleAsType_custom_match() {
215+
var err error = MyAsError{"an error"}
216+
fmt.Println("Error:", err)
217+
fmt.Printf("TypeOf err: %T\n", err)
218+
219+
pathError, ok := errors.AsType[*fs.PathError](err)
220+
fmt.Println("Error as fs.PathError:", ok)
221+
fmt.Println("fs.PathError:", pathError)
222+
223+
// Output:
224+
// Error: an error
225+
// TypeOf err: errors_test.MyAsError
226+
// Error as fs.PathError: true
227+
// fs.PathError: custom /: an error
228+
}
229+
117230
func ExampleUnwrap() {
118231
err1 := errors.New("error1")
119232
err2 := fmt.Errorf("error2: [%w]", err1)

0 commit comments

Comments
 (0)