nil
check GO-W1001In Go, interface values are type tagged, i.e., they are essentially pairs of the
form (value, type)
, where value is a non-interface value with the given type.
Such a pair is never nil
, even if the value is nil
. So, suppose a
non-interface value v
is assigned to a variable x
whose type is an interface.
In that case, x
will never be nil
. As pair (value, type)
is not nil
regardless of any value of v
(even nil
) as the type
is present.
Comparing x
to nil
is pointless, and doing so might indicate a misunderstanding
of Go interfaces or some other underlying bug.
// SingerError implements `error` interface
type SingerError struct{}
func (*SingerError) Error() string {
return ""
}
func sing(song string) (string, *SingerError)
func singer(song string) {
var m string
var e error
m, e = sing(song)
// NOTE: `e`'s comparison to nil is not correct. It is always
// non-nil in this case.
// Reason: `e` is declared to be of type `error`, an interface.
// As, `*SingerError` type is assigned to `e`'s interface tuple (value,type)
// as interface values in Go are type tagged, thus, `e` is not `nil`, unless both
// (value,type) are `nil`. But in this case, even if the value is `nil`, the type
// is non-nil i.e., `*SingerError`, hence the comparison with `nil` is not correct
// and `e`` is always `!= nil`.
if e != nil {
fmt.Printf("Unable to sing %s: %v
", song, e)
} else {
fmt.Printf("Sang %s
", m)
}
}
// SingerError implements `error` interface
type SingerError struct{}
func (*SingerError) Error() string {
return ""
}
func sing(song string) (string, *SingerError)
func singer(song string) {
m, e := sing(song)
// NOTE: Here the comparison with `nil` is correct as in this case,
// a short variable declaration (operator `:=`) is used, which will automatically
// infer the more precise non-interface type `*ResourceError` for `e`, making
// the `nil` check work as expected.
if e != nil {
fmt.Printf("Unable to sing %s: %v
", song, e)
} else {
fmt.Printf("Sang %s
", m)
}
}