Writing constant errors with Go 1.13

package ximport (
"fmt"
)
// Errors raised by package x.
var (
ErrPermissionDenied = fmt.Errof("permission denied")
ErrInvalidParameters = fmt.Errof("invalid parameters")
)
package xvar constError stringfunc (err constError) Error() string {
return string(err)
}
// Errors raised by package x.
const (
ErrPermissionDenied = constError("permission denied")
ErrInvalidParameters = constError("invalid parameters")
)
package x// Foo is guaranteed to return an error.
func Foo(s string) error {
if s != "bar" && s != "baz" {
err := errors.New("s not in [bar baz]")
return fmt.Errof("%s: %v", ErrInvalidParameters, err)
}
return ErrPermissionDenied
}
err := x.Foo(v)
switch err {
case ErrInvalidParameters: // will never match
// Handle error ...
case ErrPermissionDenied: // will match if raised
// Handle error ...
}
err := x.Foo(v)
switch {
case x.IsErrInvalidParameters(err): // Package specific handling
// Handle error ...
case err == ErrPermissionDenied:
// Handle error ...
}

Enter Go 1.13

package ximport (
"fmt"
"strings"
)
// Errors raised by package x.
var (
ErrPermissionDenied = wrapError{msg:"permission denied"}
ErrInvalidParameters = wrapError{msg:"invalid parameters"}
)
type wrapError struct {
err Error
msg string
}
func (err wrapError) Error() string {
if err.err != nil {
return fmt.Sprintf("%s: %v", err.msg, err.err)
}
return err.msg
)}
func(err wrapError) wrap(inner error) error {
return wrapError{msg: err.msg, err: inner}
}
func (err wrapError) Unwrap() error {
return err.err
}
func (err wrapError) Is(target error) bool {
ts := target.Error()
return ts == err.msg || strings.HasPrefix(ts, err.msg + ": ")
}
package xfunc Foo(s string) error {
if s != "bar" && s != "baz" {
err := errors.New("s not in [bar baz]")
return ErrInvalidParams.wrap(err)
}
return ErrPermissionDenied
}
err := x.Foo(v)
switch {
case errors.Is(err, ErrInvalidParameters): // will match if raised
case errors.Is(err, ErrPermissionDenied): // will match if raised
}

Equal values, different types

package ximport (
"fmt"
"strings"
)
// Errors raised by package x.
var (
ErrPermissionDenied = constError("permission denied")
ErrInvalidParameters = constError("invalid parameters")
)
type constError stringfunc (err constError) Error() string {
return string(err)
}
func (err constError) Is(target error) bool {
ts := target.Error()
es := string(err)
return ts == es || strings.HasPrefix(ts, es+": ")
}
func (err constError) wrap(inner error) error {
return wrapError{msg: string(err), err: inner}
}
type wrapError struct {
err error
msg string
}
func (err wrapError) Error() string {
if err.err != nil {
return fmt.Sprintf("%s: %v", err.msg, err.err)
}
return err.msg
}
func (err wrapError) Unwrap() error {
return err.err
}
func (err wrapError) Is(target error) bool {
return constError(err.msg).Is(target)
}

Conclusion

--

--

--

Backend developer at Searis AS, and occasional tech blogger.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Sparkify: Dear Users, Stay with Us

The Good, The Bad, And Alerting on Derivatives

Make your application scalable with Laravel Queues — from the basics to Horizon

Get Better IT Solutions By Sharing Your Business Processes

Details of Go JSON serialization of []byte type

Authorization with Firebase Authentication, NodeJS and React

Some light on Magic (or Dunder) Methods in Python

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Sindre Myren

Sindre Myren

Backend developer at Searis AS, and occasional tech blogger.

More from Medium

Fuzz Testing in Go

Pointer assignment is not atomic in Go

Option Pattern implementation in Go

Unit testing in Go using Mockery