An interface value is nil
only if the V
and T
are both unset - T=nil, V is not set
Although an interface is nil
by default, if we store a nil
pointer (e.g. of type *int
) as the value for an interface, the interface's type will be *int
regardless of the underling value of the pointer. Thus, the interface itself will be non-nil
even though the pointer's value is nil
.
An interface value that holds a nil concrete value is itself non-nil If the concrete value inside the interface itself is nil, the method will be called with a nil receiver.
var p *int var i DocsInterface i = p // i is now T=*int,V=memory address, *i = nil // i is non-nil
This also works when not talking about simple pointers, e.g. a type
, pointer to a struct
, etc. When the value is converted into an interface, the interface becomes non-nil
as it's storing the type, even though the underlying value is nil
. If the interface is used as an argument to a method, the interface datastructure is created when called, which uses the value of whatever is satisfying the interface.
In this case, VError
implements the interface of error
. When passing something of type VError
to a function that had an error
interface as an argument, the value passed will always be non-nil as the interface will be storing T=VError
, even if V
is nil.
func (e Error) Error() {
// implementation not important, but this satisfies the interface
}
type VError map[string]string // same is VError was a struct and verr was verr = *VError
func doSomethingWithAnError(e error) {
// ...
}
var err error
var verr VError
err = verr
fmt.Printf("err: %T %#v \n", err, err) // main.VError main.VError(nil)
fmt.Printf("err2: %T %#v \n", err2, err2) // <nil> <nil>
fmt.Printf("verr == nil: %v \n", verr == nil) // true
fmt.Printf("err == nil: %v \n", err == nil) // false
doSomethingWithAnError(err) // this will pass a non-nil value