2015-05-11 7 views
7

Im folgende Codestück, schlägt mit dem folgenden Fehler eine Null-Schnittstelle auf einen Zeiger von etwas zu konvertieren versuchen: interface conversion: interface is nil, not *main.NodeNil-Schnittstelle in Pointer von etwas in Golang konvertieren?

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 
} 

Wiedergabe Link hier: https://play.golang.org/p/2cgyfUStCI

Warum funktioniert das nicht genau das? Es ist durchaus möglich

n = (*Node)(nil) 

zu tun, so frage ich mich, wie können Sie einen ähnlichen Effekt erzielen aus einer Null-Schnittstelle starten. Diese

Antwort

21

ist, weil eine Variable statischen Typ Nexter (die nur eine Schnittstelle ist) kann Werte von vielen verschiedenen Typen dynamischen halten.

Ja, da *NodeNexter implementiert, Ihre p Variable Typ einen Wert von möglicherweise *Node, halten, aber es kann andere Arten als auch die Nexter implementieren halten; oder es kann nichts überhaupt halten (nil Wert). Und Type assertion kann hier nicht verwendet werden, da aus der spec zitieren:

x.(T) asserts that x is not nil and that the value stored in x is of type T .

Aber x in Ihrem Fall ist nil. Und wenn die Typassertion falsch ist, tritt eine Laufzeitpanik auf.

Wenn Sie Ihr Programm ändern Ihre p Variable zu initialisieren:

var p Nexter = (*Node)(nil) 

Ihr Programm ausgeführt wird, und geben Behauptung erfolgreich ist. Dies liegt daran, dass ein Schnittstellenwert tatsächlich ein Paar in der folgenden Form enthält: (value, dynamic type), und in diesem Fall wird p nicht nil sein, sondern ein Paar (nil, *Node); Details siehe The Laws of Reflection #The representation of an interface.

Wenn Sie auch nil Werte von Schnittstellentypen zu handhaben möchten, können Sie es so explizit überprüfen:

if p != nil { 
    n = p.(*Node) // will not fail IF p really contains a value of type *Node 
} 

Oder besser: Verwenden Sie die spezielle "Komma-ok" Form:

// This will never fail: 
if n, ok := p.(*Node); ok { 
    fmt.Printf("n=%#v\n", n) 
} 

Verwendung des "Komma-OK" -Formulars:

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.