2

値の 1 つが nil の場合、マップをポインターにエンコードしようとすると、Gob の Encode がエラーを返します。これはドキュメントと矛盾しているようです(ただし、意味を誤解している可能性があります):

スライスと配列、およびマップでは、たとえすべての要素がゼロであっても、すべての要素 (値がゼロの要素も含む) が転送されます。

コード:

package main

import (
    "bytes"
    "encoding/gob"
)

type Dog struct {
    Name string
}

func main() {
    m0 := make(map[string]*Dog)
    m0["apple"] = nil

    // Encode m0 to bytes
    var network bytes.Buffer
    enc := gob.NewEncoder(&network)
    err := enc.Encode(m0)
    if err != nil {
        panic(err) // Output: panic: gob: encodeReflectValue: nil element
    }
}

出力:

panic: gob: encodeReflectValue: nil element

この場合、ゴブが失敗する正当な理由はありますか? 2 つの明白なオプションのどちらかが失敗よりも望ましいようです: 1) ゼロ値の値を持つキーをエンコードしない、または 2) 値がゼロ値であってもすべてのキーをエンコードします。現在の状態では、構造体を再帰的にスキャンして nil マップ値があるかどうかを確認し、ある場合はそれらのキーを削除するのがベスト プラクティスですか? このチェックが必要な場合は、ユーザーではなく、encoding/gob パッケージの責任であるように思われます。

さらに、値の型がスライスの場合は nil が受け入れられるため、ルールは単純に「キーの値が nil のマップを gob でエンコードできない」というわけではありません。

func main() {
    m0 := make(map[string][]string)
    m0["apple"] = nil

    // Encode m0 to bytes
    var network bytes.Buffer
    enc := gob.NewEncoder(&network)
    err := enc.Encode(m0) // err is nil
    if err != nil {
        panic(err) // doesn't panic
    }
}
4

1 に答える 1

4

エンコードされたgobストリームには、ポインターの概念がありません。のようなポインター値をエンコードすると、*intポイントされた値、つまり型の値が送信されますint。この変換は、必要に応じてデコーダ側で逆に行われます。たとえば、値が設定さintれるストリームで値が見つかった場合、デコードされた値を指す*intポインタ (タイプ*int) が設定されintます。

したがって、ポインター値自体がnilである場合、gobパッケージがポインター値の代わりにエンコードできる値はなく、ポインターnilは何も指していません。ポインターを逆参照するnilと、ランタイム パニックが発生します。

これはgob: Basicsにも記載されています。

ポインタは送信されませんが、ポインタが指すものは送信されます。つまり、値は平坦化されます。値がないため、nil ポインターは許可されません。

于 2018-06-06T16:39:34.147 に答える