1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
package config
import (
"errors"
"fmt"
)
var NotInitialized error = errors.New("your application config not initialized")
var VersionMismatch error = errors.New("your PB version does not match")
// Finally, declare a package-level variable of your new type.
// This is the "sentinel" error that users will compare against.
var ErrNotInitialized = NotInitializedError{}
func ErrdKeyFalse(varname string) error {
return errors.New("config key '" + varname + "' was not 'true'")
}
func ErrdKeyNotSet(varname string) error {
return errors.New("config key '" + varname + "' was not set")
}
// thanks gemini for this example custom error example
// --- 1. A Custom Error Type for "Not Initialized" ---
// First, define a new, named type for your error. A struct is common.
type NotInitializedError struct{}
// Now, attach the Error() method to your new type. This makes it
// satisfy the built-in 'error' interface.
func (e NotInitializedError) Error() string {
return "your application config not initialized"
}
// (Your Goal) Attach a custom String() method for pretty printing.
// This will be used by fmt.Println, for example.
func (e NotInitializedError) String() string {
return "func main() didn't initialize this"
}
// --- 2. A Custom Error Type with an Is() Method ---
// Let's make a more complex error for key-not-set issues.
type KeyNotSetError struct {
KeyName string // It can hold data!
}
// Make it satisfy the 'error' interface.
func (e KeyNotSetError) Error() string {
return fmt.Sprintf("config key '%s' was not set", e.KeyName)
}
// (Your Goal) Define a custom Is() method.
// errors.Is(someError, ErrKeyNotSet) will call this method.
func (e KeyNotSetError) Is(target error) bool {
// We can check if the target is of the same type.
// This allows errors.Is(err, KeyNotSetError{}) to work,
// checking for the general *type* of error.
_, ok := target.(KeyNotSetError)
return ok
}
// A helper function to create this error.
func NewKeyNotSetError(varname string) error {
return KeyNotSetError{KeyName: varname}
}
// A generic sentinel error for this category.
var ErrKeyNotSet = KeyNotSetError{}
/*
// --- Example Usage ---
func checkConfig() error {
// Pretend the config is not initialized.
return ErrNotInitialized
}
func checkKey(key string) error {
// Pretend a specific key is not set.
return NewKeyNotSetError(key)
}
func main() {
// --- Test Case 1: The NotInitializedError ---
err1 := checkConfig()
// errors.Is() works perfectly because it compares the variable directly.
if errors.Is(err1, ErrNotInitialized) {
fmt.Println("Check 1: errors.Is correctly identified ErrNotInitialized.")
}
// fmt.Println will use your custom String() method!
fmt.Println("Check 2: Printing the error uses the custom String() method:")
fmt.Println(err1)
fmt.Println()
// --- Test Case 2: The KeyNotSetError ---
err2 := checkKey("database_url")
// This works because of your custom Is() method!
// We are checking if err2 is of the *type* KeyNotSetError.
if errors.Is(err2, ErrKeyNotSet) {
fmt.Println("Check 3: errors.Is correctly identified the general KeyNotSetError type.")
}
// You can also get the underlying error to inspect its data.
var keyErr KeyNotSetError
if errors.As(err2, &keyErr) {
fmt.Printf("Check 4: errors.As extracted the error data. Key not set: %s\n", keyErr.KeyName)
}
}
*/
|