次のコードでは、nilインターフェイスを何かのポインターに変換しようとすると、次のエラーで失敗します: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
}
ここでリンクを再生: https://play.golang.org/p/2cgyfUStCI
なぜこれは正確に失敗するのですか?それは完全に可能です
n = (*Node)(nil)
、それで私はあなたがnilインターフェースから始めて同様の効果をどのように達成できるのか疑問に思っています。
これは、 static タイプNexter
(単なるインターフェース)の変数が、さまざまな dynamic タイプの値を保持できるためです。
はい、_*Node
_はNexter
を実装しているため、p
変数は may タイプ_*Node
_の値を保持しますが、その他のタイプ同様にNexter
を実装します。または、 nothing を保持する場合があります(nil
value)。そして Type assertion は、仕様から引用しているため、ここでは使用できません。
x.(T)
は、x
がnotnil
であり、x
に格納されている値がT
型であることをアサートします。
しかし、あなたの場合のx
はnil
です。そして、型アサーションがfalseの場合、ランタイムパニックが発生します。
プログラムを変更してp
変数を次のように初期化する場合:
_var p Nexter = (*Node)(nil)
_
プログラムが実行され、型のアサーションが成功します。これは、インターフェイス値が実際に_(value, dynamic type)
_の形式でペアを保持しているためです。この場合、p
はnil
ではなく、_(nil, *Node)
_のペアを保持します。詳細は 反射の法則#インターフェースの表現 を参照してください。
インターフェイスタイプのnil
値も処理する場合は、次のように明示的に確認できます。
_if p != nil {
n = p.(*Node) // will not fail IF p really contains a value of type *Node
}
_
以上:特別な「コンマOK」形式を使用します。
_// This will never fail:
if n, ok := p.(*Node); ok {
fmt.Printf("n=%#v\n", n)
}
_
「コンマOK」フォームを使用する:
アサーションが成立する場合、
ok
の値はtrue
です。それ以外の場合はfalse
であり、n
の値はT
型のゼロ値です。 この場合、実行時パニックは発生しません。