Consider the following program. What do you think will be printed? true
or false
?
package main
type MyInterface interface {
DoSomething()
}
type MyInterfaceImplementation struct{}
func (impl *MyInterfaceImplementation) DoSomething() {}
func getMyInterfaceImplementation() *MyInterfaceImplementation {
return nil
}
func getMyInterface() MyInterface {
return getMyInterfaceImplementation()
}
func main() {
fmt.Println(getMyInterface() == nil)
}
If you said true
you will be surprised to find out that it's actually false
.
Let's print out what's returned by getMyInterface()
func main() {
fmt.Printf("%v %t\n", getMyInterface(), getMyInterface() == nil)
}
$ <nil> false
That doesn't make any sense! We are getting a nil
but the equality check with nil
returns false
. Why? Let's dig in a little deeper.
func main() {
fmt.Printf("%#v %t\n", getMyInterface(), getMyInterface() == nil)
}
$ (*main.MyInterfaceImplementation)(nil) false
If you have a variable whose type is an interface that variable is actually storing an interface value, NOT the value that you set it to. The same applies when your function returns a value of an interface type.
In the Go runtime interface values are implemented as tuples, meaning it is made up of two things. The first is the concrete type of the interface (here it is *main.MyInterfaceImplementation
) and the second is the concrete value (nil
). This is how the Go runtime tracks which interface implementation is being referenced and where the value is in memory, or if it nil.
So getMyInterface()
is not returning a nil
but rather an interface value whose concrete value is nil
. If we want our function to return a nil
instead we need to make the following change.
func getMyInterface() MyInterface {
impl := getMyInterfaceImplementation()
if impl == nil {
return nil
}
return impl
}
$ <nil> true
Top comments (0)