Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert nil interface to pointer of something in Golang?

Tags:

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.

like image 544
Mihnea Giurgea Avatar asked May 11 '15 07:05

Mihnea Giurgea


People also ask

Can pointer be nil Golang?

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.

Can an interface be nil Golang?

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.

How do I assign a nil value in Golang?

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.

What can be nil in Golang?

nil can represent zero values for several types like pointer types, map types, slice types, function types, channel types, interface types, and so on.


1 Answers

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 that x is not nil and that the value stored in x is of type T.

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 is true if the assertion holds. Otherwise it is false and the value of n is the zero value for type T. No run-time panic occurs in this case.

like image 182
icza Avatar answered Oct 12 '22 15:10

icza