Dans le code suivant, la tentative de conversion d'une interface nil en un pointeur de quelque chose échoue avec l'erreur suivante: 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
}
Lien de lecture ici: https://play.golang.org/p/2cgyfUStCI
Pourquoi cela échoue-t-il exactement? Il est tout à fait possible de faire
n = (*Node)(nil)
, je me demande donc comment obtenir un effet similaire à partir d'une interface nulle.
En effet, une variable de type statique type Nexter
(qui n'est qu'une interface) peut contenir des valeurs de nombreux types dynamique différents.
Oui, puisque *Node
Implémente Nexter
, votre p
variable may contient une valeur de type *Node
, Mais elle peut hold autres types ainsi qui implémentent Nexter
; ou il peut contenir rien du tout (nil
value). Et Assertion de type ne peut pas être utilisé ici car citation de la spécification:
x.(T)
affirme quex
n'est pas pasnil
et que la valeur stockée dansx
est de typeT
.
Mais x
dans votre cas est nil
. Et si l'assertion de type est fausse, une panique au moment de l'exécution se produit .
Si vous modifiez votre programme pour initialiser votre variable p
avec:
var p Nexter = (*Node)(nil)
Votre programme s'exécutera et l'assertion de type réussira. En effet, une valeur d'interface contient en fait une paire sous la forme de: (value, dynamic type)
, Et dans ce cas, votre p
ne sera pas nil
, mais contiendra une paire de (nil, *Node)
; pour plus de détails, voir Les lois de la réflexion #La représentation d'une interface .
Si vous souhaitez également gérer les valeurs nil
des types d'interface, vous pouvez le vérifier explicitement comme ceci:
if p != nil {
n = p.(*Node) // will not fail IF p really contains a value of type *Node
}
Ou mieux: utilisez le formulaire spécial "virgule-ok":
// This will never fail:
if n, ok := p.(*Node); ok {
fmt.Printf("n=%#v\n", n)
}
Utilisation du formulaire "virgule-ok":
La valeur de
ok
esttrue
si l'assertion est vraie. Sinon, c'estfalse
et la valeur den
est la valeur zéro pour le typeT
. Aucune panique d'exécution ne se produit dans ce cas.