web-dev-qa-db-ja.com

nilインターフェースをGolangの何かのポインターに変換しますか?

次のコードでは、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インターフェースから始めて同様の効果をどのように達成できるのか疑問に思っています。

14
Mihnea Giurgea

これは、 static タイプNexter(単なるインターフェース)の変数が、さまざまな dynamic タイプの値を保持できるためです。

はい、_*Node_はNexterを実装しているため、p変数は may タイプ_*Node_の値を保持しますが、その他のタイプ同様にNexterを実装します。または、 nothing を保持する場合があります(nil value)。そして Type assertion は、仕様から引用しているため、ここでは使用できません。

x.(T)は、xnot nilであり、xに格納されている値がT型であることをアサートします。

しかし、あなたの場合のxnilです。そして、型アサーションがfalseの場合、ランタイムパニックが発生します

プログラムを変更してp変数を次のように初期化する場合:

_var p Nexter = (*Node)(nil)
_

プログラムが実行され、型のアサーションが成功します。これは、インターフェイス値が実際に_(value, dynamic type)_の形式でペアを保持しているためです。この場合、pnilではなく、_(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型のゼロ値です。 この場合、実行時パニックは発生しません。

31
icza