type error interface {
Error() string
}
Error() method if we want totype errType int
const (
_ errType = iota
noHeader
invalidBody
)
type SomeError struct {
kind errType
pos int
err error // some other underlying error
}
// implement the Error method for our new error
func (e SomeError) Error() {
switch e.kind {
case noHeader {
return "No header"
}
case invalidBody {
return "Invalid body"
}
}
}
// we can define our own methods on our custom error, e.g. building an error with value
func (e SomeError) with(pos int) SomeError {
e1 = e
e1.pos = pos
return e1
}
// a useful pattern is to define "prototype" errors that we can then adapt using methods like above, e.g.
var (
HeaderMissing = SomeError{kind: noHeader}
BodyMissing = SomeError{kind: invalidBody}
)
// then if we have an invalid body we can specify a position for the error using the adapter:
BodyMissing.with(105)
fmt.Errorf("This is the wrapped error: %w", someErr) to create a wrapped errorerrors.Is(err, target error) to see whether any error in err’s tree matches the target
Is() method for our custom error types that allows determination of whether the error is of a certain type
errors.Is() the logic for checking this is if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) { return true }func (e *SomeError) Is(t error) bool {
castErr, ok := t.(*SomeError)
if !ok {
return false
}
// here we check the internal kind of that errType defined above
return castErr.kind == e.kind
}
errors.As()if audio, err = DecodeWaveFile(fn); err != nil {
var e os.PathError
if errors.As(err, &e) {
// ... do something with e
}
}
os.PathError from the chain of errAs() has similar logic to Is(): if x, ok := err.(interface{ As(any) bool }); ok && x.As(target) { return true }As() method for our custom error similar to Is if we need that functionality, otherwise the library will just use reflection to determine the equality of types and set iterror type, these should be handled by our program gracefullypanic functionpanic is always a last resort and is a fail hard, fail fast mechanism
panicpanic is similar to assert in other programming languagespanic and recoverpanic and recoverpanic only in a defer block using recover():func abc() {
panic("omg")
}
func main() {
defer func() {
if p := recover(); p != nil {
// can't really do much else here other than print
fmt.Println("recover: ", p)
}
}()
abc()
}
panic, there isn’t much we can do other than print, since our program is in a corrupt state and we can’t trust our assumptions any moreif err != nil is outweighed by the value of deliberately handling each failure condition at the point at which it occurs