Go Typed Nil
Why an interface holding a nil pointer is not itself nil in Go, and how typed nils can cause unexpected behavior.
The following code doesn’t do what you might expect:
package main
import "fmt"
func main() {
var i *impl
fmt.Println("i == nil:", i == nil)
what(i)
}
type impl struct{}
func (i *impl) do() {}
func what(i interface{ do() }) {
fmt.Println("i == nil:", i == nil)
}
If you expected the what function to print i == nil: true, then keep
reading…
🕳️ Typed Nils
The behavior observed is due to the way interfaces and nil values interact in
Go. To understand why the what function is able to see the i argument as
non-nil, we need to dig into the details of how Go handles interface values.
- Interface Values: In Go, an interface value is a tuple of a type and a value.
An interface value is
nilonly if both the type and the value arenil. - Concrete vs Interface nil: When you assign a concrete type value (which
happens to be
nil) to an interface, the interface itself is notnil. This is because the interface value now contains a type (the concrete type) and a value (nil).
💡 Explanation
- Declaring
var i *implinitializes it tonil.iis a pointer toimpland is initialized tonil.
- Printing
i == nilinmainistrue- because
iis anilpointer toimpl
- because
- Calling
what(i)function:- the function
whattakes an argument of typeinterface{ do() }
- the function
- Inside
whatfunction:i(which isnil) is passed towhat- it is assigned to the parameter
iof typeinterface{ do() }
- Interface value construction:
The value ofiinsidewhatis now an interface that holds:- Type:
*impl(the concrete type of the value passed in) - Value:
nil(the value of the concrete type)
- Type:
- Checking
i == nilprintsfalsebecause the interfaceiis notnil:- The type part of the interface is
*impl. - The value part of the interface is
nil.
- The type part of the interface is
📋 Summary
The what function sees the i argument as non-nil because, in Go, an
interface holding a nil pointer is not itself nil. The interface contains
type information (*impl) and a nil value. Therefore, when the code checks if
i is nil, it returns false since the type information (*impl) is
present.