This should be a gimme for someone. Why do I not get what I expect ("Error is not nil") here?
http://play.golang.org/p/s8CWQxobVL
type Goof struct {}
func (goof *Goof) Error() string {
return fmt.Sprintf("I'm a goof")
}
func TestError(err error) {
if err == nil {
fmt.Println("Error is nil")
} else {
fmt.Println("Error is not nil")
}
}
func main() {
var g *Goof // nil
TestError(g) // expect "Error is nil"
}
This is, it turns out, a Frequently Asked Question about Go, and the short answer is that interface comparisons compare the type and the value, and (*Goof)(nil)
and error(nil)
have different types.
Since if err != nil
is standard, you want a return value that'll work with it. You could declare var err error
instead of var g *Goof
: err
's zero value is conveniently error(nil)
Or, if your func returns an error
, return nil
will return what you want.
For more background, here's the start of the FAQ's answer:
Under the covers, interfaces are implemented as two elements, a type and a value. The value, called the interface's dynamic value, is an arbitrary concrete value and the type is that of the value. For the
int
value3
, an interface value contains, schematically,(int, 3)
.An interface value is
nil
only if the inner value and type are both unset,(nil, nil)
. In particular, anil
interface will always hold anil
type. If we store a pointer of type*int
inside an interface value, the inner type will be*int
regardless of the value of the pointer:(*int, nil)
. Such an interface value will therefore be non-nil
even when the pointer inside isnil
.
And ==
is strictly checking if the types are identical, not if a type (*Goof
) implements an interface (error
). Check out the original for more.
If it helps clarify, this doesn't only happen with nil
: in this example, the data underlying the x
and y
variables is obviously 3
, but they have different types. When you put x
and y
into interface{}
s, they compare as unequal:
package main
import "fmt"
type Bob int
func main() {
var x int = 3
var y Bob = 3
var ix, iy interface{} = x, y
fmt.Println(ix == iy)
}