Consider the following (demo https://go.dev/play/p/VrJx-eEij14)
type myError struct {
err error
}
func (e myError) Error() string { return e.err.Error() }
func main() {
var (
err error = fmt.Errorf("%w", myError{errors.New("I am an error")})
nilErr error = nil
errAny any = err
nilErrAny any = nilErr
)
{
recErr, ok := errAny.(error)
fmt.Println(recErr, ok)
}
{
recErr, ok := nilErrAny.(error)
fmt.Println(recErr, ok)
}
}
It prints
I am an error true
<nil> false
while I expected it to print
I am an error true
<nil> true
Trying the same exercice replacing the interface type error
with *int
(demo https://go.dev/play/p/NtHVyYO9Hfj)
func main() {
var (
p *A = &A{}
nilp *A = nil
pAny any = p
nilpAny any = nilp
)
{
rec, ok := pAny.(*A)
fmt.Println(rec, ok)
}
{
rec, ok := nilpAny.(*A)
fmt.Println(rec, ok)
}
}
does yield to the output I expect
&{} true
<nil> true
Why can one recover a nil int pointer from an empty interface but not a nil error from an empty interface?
FYI, the specific situation I am trying to solve is one, where I am caching errors. The values cached are of type any
. Some errors cached are nil
. I care about the difference between a nil
error and an object that I could unexpectedly not type assert into an error because I would have messed my cache up.