Description
I am reading about how to use the new Go errors code. In this blog post, there's the following example:
// The As function tests whether an error is a specific type.
// Similar to:
// if e, ok := err.(*QueryError); ok { … }
var e *QueryError
if errors.As(err, &e) {
// err is a *QueryError, and e is set to the error's value
}
My initial read was that this can't be right - it's taking the address of a *QueryError
, which gives a **QueryError
, which a) does not match the type of the "Similar to" immediately above it, and b) a pointer to a pointer is almost never what you want in Go.
However I wrote some tests and yeah a **QueryError
is actually what we want here:
type QueryError struct{}
func (e *QueryError) Error() string {
return "an error occurred"
}
func TestErrorsAs(t *testing.T) {
q1 := new(QueryError)
subErr := fmt.Errorf("a sub error occurred: %w", q1)
var q2 *QueryError
fmt.Printf("%#v\n", &q2)
if errors.As(subErr, &q2) {
fmt.Println("subErr unwraps to q2")
} else {
t.Fatal("errors.As comparison failure")
}
}
The blog post doesn't really mention this weirdness at all though.
I presume some folks like me are going to out of instinct remove either the *
or the &
in order to get one layer of nesting and then be confused when that's not correct. It might be good to add a note that, yes, this is the correct thing to do.