Error
Errors
fmt also expects the Error interface to be implemented on error types
Basic example
func (w *Wallet) Withdraw(amount Bitcoin) error {
if amount > w.balance {
return errors.New("overdrawn")
}
w.balance -= amount
return nil
}
// test
t.Run("Withdraw too much", func(t *testing.T) {
wallet := Wallet{}
wallet.Deposit(1)
err := wallet.Withdraw(3)
if err == nil {
t.Errorf("expected an error to occur")
}
if err.Error() != "overdrawn" {
t.Errorf("wrong error message")
}
})Custom errors
To make an error type you just need to implement the error interface.
This pattern makes errors immutable and reusable.
type DictionaryErr string
const (
ErrUnknownKey = DictionaryErr("unknown key")
ErrKeyAlreadyExists = DictionaryErr("key already exists")
)
func (e DictionaryErr) Error() string {
return string(e)
}
type Dictionary map[string]string
func (d *Dictionary) Search(key string) (string, error) {
def, ok := (*d)[key]
if !ok {
return "", ErrUnknownKey
}
return def, nil
}Error formatter
func Racer(a, b string, timeout time.Duration) (winner string, error error) {
select {
case <-ping(a):
return a, nil
case <-ping(b):
return b, nil
case <-time.After(timeout):
return "", fmt.Errorf("timed out waiting for %s and %s", a, b)
}
}Structured errors
type CustomError struct {
customMessage string
}
func (e CustomError) Error() string {
return fmt.Sprintf("well the bloody thing broke, %q", e.customMessage)
}
func ErrorProducer() error {
return CustomError{customMessage: "it broke"}
}
// -------------------------------------
func ExampleErrorProducer() {
got := ErrorProducer()
if customErr, ok := errors.AsType[CustomError](got); ok {
fmt.Println("match:", customErr.customMessage)
}
// Output: match: it broke
}