hi all,
Im relatively new to go (but been a developer for over 15yrs) and wrote some code like this and it perplexed me for a couple hours.
var _ error = &Error{}
type Error struct{ message string }
func (e *Error) Error() string { return e.message }
func call1() error { return call2() }
func call2() *Error { return nil }
func Test_Gotcha(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("Failed with a panic for null usage")
}
}()
err := call1()
if err != nil {
anError, ok := err.(*Error)
if ok {
fmt.Printf("this panics on nil reference %s\n", anError.message)
}
}
}
Im wondering what the logic is behind the err!=nil not catching the <*Error> nil returned from call2?
Go seems straight pretty easy and straight forward most of the time but this seems to be a gotcha in a really bad place?
PS Im using go 13.1
One bit of the logic behind it is that nil pointers in Go aren’t always as “bad” as in other languages. For example it’s ok to call methods on nil pointers, and those methods can do useful things. This means that having an interface with T=*foo V=nil might be a useful and intended thing. Hence the nil interface is strictly the one that has no type (nor value).
In another sense it would be odd for an interface to be nil yet contain information (the type). As it is, nil strictly means the zero value which is simple and easy to understand - although it causes this annoying caveat with errors.