In the following code piece, trying to convert a nil interface to a pointer of something fails with the following error: interface conversion: interface is nil, not *main.Node
type Nexter interface { Next() Nexter } type Node struct { next Nexter } func (n *Node) Next() Nexter {...} func main() { var p Nexter var n *Node fmt.Println(n == nil) // will print true n = p.(*Node) // will fail }
Play link here: https://play.golang.org/p/2cgyfUStCI
Why does this fail exactly? It's entirely possible to do
n = (*Node)(nil)
, so I'm wondering how can you achieve a similar effect starting from a nil interface.
Nil Pointers All variables in Go have a zero value. This is true even for a pointer. If you declare a pointer to a type, but assign no value, the zero value will be nil . nil is a way to say that “nothing has been initialized” for the variable.
Under the hood, an interface in Golang consists of two elements: type and value. When we assign a nil integer pointer to an interface in our example above, the interface becomes (*int)(nil) , and it is not nil. An interface equals nil only if both the type and value are nil.
Nil represents a zero value in Golang. As you may already know, zero values are the "default" value for defined variables in Go. This means that some types doesn't cannot hold empty values, instead acquiring zero values upon initialization to get rid of the problem of checking values for emptyness.
nil can represent zero values for several types like pointer types, map types, slice types, function types, channel types, interface types, and so on.
This is because a variable of static type Nexter
(which is just an interface) may hold values of many different dynamic types.
Yes, since *Node
implements Nexter
, your p
variable may hold a value of type *Node
, but it may hold other types as well which implement Nexter
; or it may hold nothing at all (nil
value). And Type assertion cannot be used here because quoting from the spec:
x.(T)
asserts thatx
is notnil
and that the value stored inx
is of typeT
.
But x
in your case is nil
. And if the type assertion is false, a run-time panic occurs.
If you change your program to initialize your p
variable with:
var p Nexter = (*Node)(nil)
Your program will run and type assertion succeeds. This is because an interface value actually holds a pair in the form of: (value, dynamic type)
, and in this case your p
will not be nil
, but will hold a pair of (nil, *Node)
; for details see The Laws of Reflection #The representation of an interface.
If you also want to handle nil
values of interface types, you may check it explicitly like this:
if p != nil { n = p.(*Node) // will not fail IF p really contains a value of type *Node }
Or better: use the special "comma-ok" form:
// This will never fail: if n, ok := p.(*Node); ok { fmt.Printf("n=%#v\n", n) }
Using the "comma-ok" form:
The value of
ok
istrue
if the assertion holds. Otherwise it isfalse
and the value ofn
is the zero value for typeT
. No run-time panic occurs in this case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With