If we want to check if a given error matches another specific error, we need to use Is() function from the errors package. If we are interested in whether the error is of a given type, we should call the As() function.
Within main() , we call doRequest() which returns an error interface to us. We first print the error message returned by the Error() method. Next, we attempt to expose all methods from RequestError by using the type assertion re, ok := err. (*RequestError) .
Go solves the exception problem by not having exceptions. Instead Go allows functions to return an error type in addition to a result via its support for multiple return values. By declaring a return value of the interface type error you indicate to the caller that this method could go wrong.
try: int("string") #the code that raises the error except ValueError: raise ValueError("Your custom message here.")
Reading the Blog post further exposes a bit of Go like this:
serr, ok := err.(*model.ModelMissingError)
This is the comma ok idiom, clearly I need to re do my go lang tour
I have manged to make an error assertion using the switch statement as follows:
err := FuncModelMissingError()
switch t := err.(type) {
default:
fmt.Println("not a model missing error")
case *ModelMissingError:
fmt.Println("ModelMissingError", t)
}
I hope this helps you out.
Now with Go 1.13 we can use the following from the errors
package:
if errors.Is(err, model.ModelMissingError) {...}
See the blog post: https://blog.golang.org/go1.13-errors
To check the TYPE of the error, use errors.As
As
finds the first error in err's chain that matches target [...] An error matches target if the error's concrete value is assignable to the value pointed to by target
Of course type identity is a condition for assignability.
So it would look like:
target := &model.ModelMissingError{}
if errors.As(err, &target) {
fmt.Println(target) // no model found for id
}
Pay attention to the two uses of &
in the example above. This is because:
As
panics if target is not a non-nil pointer to either a type that implements error, or to any interface type.
In your case, you declared Error() string
method on the pointer receiver, therefore "a pointer to the type that implements the error
interface" to satisfy As
is **ModelMissingError
. So you need to address twice.
The other method errors.Is
checks for value equality.
An error is considered to match a target if it is equal to that target or if it implements a method Is(error) bool such that Is(target) returns true.
This is useful for example in case of fixed error values, e.g. errors declared as var
or const
like the standard library io.EOF
. As an example:
var ErrModelMissing = errors.New("no model found for id")
func foo() {
err := bar()
if errors.Is(err, ErrModelMissing) {
fmt.Println(err) // no model found for id
}
}
Consider that the usefulness of Go 1.13 errors.As
and errors.Is
lies in error unwrapping. If you inspect the error at the top of an arbitrarily long call stack, you must remember that the original error may become wrapped into other errors while being bubbled up. Then directly checking for equality or type assignability is not enough.
err1 := fmt.Errorf("wrapped: %w", &ModelMissingError{})
target := &ModelMissingError{}
fmt.Println(errors.As(err1, &target)) // true
err2 := fmt.Errorf("wrapped: %w", FixedError)
fmt.Println(errors.Is(err2, FixedError)) // true
fmt.Println(err2 == FixedError) // false
Additionally, the package github.com/pkg/errors
is compatible with errors.As
and errors.Is
:
// import pkgerr "github.com/pkg/errors"
err3 := pkgerr.Wrap(pkgerr.Wrap(&ModelMissingError{}, "wrapped 1"), "wrapped 2")
fmt.Println(errors.As(err3, &target)) // true
Playground: https://play.golang.org/p/FEzggdBLCqq
Naturally, if you know for sure that the error is not wrapped, a good old type assertion works just as fine:
if myerr, ok := err.(*model.ModelMissingError); ok {
// handle myerr
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With