gob 试图解码 nil 值导致 EOF 错误

gob attempting to decode nil value results in EOF error

我需要使用 gob 来编码一些数据,但是,我发现 "type nil" 无法正确处理(转到 1.6.2)

https://play.golang.org/p/faypK8uobF

package main

import (
    "bytes"
    "encoding/gob"
    "log"
)

type T struct {
    A int
}

func init() {
    gob.Register(map[string]interface{}{})
    gob.Register(new(T))
}
func main() {
    bys := bytes.NewBuffer(nil)
    gob.NewEncoder(bys).Encode(map[string]interface{}{
        "v": (*T)(nil),
    })
    out := map[string]interface{}{}
    if err := gob.NewDecoder(bys).Decode(&out); err != nil {
        log.Panic(err)
    }
    return
}

输出:

panic: EOF

您正在吞下 Encoder.Encode() 返回的 error

err := gob.NewEncoder(bys).Encode(map[string]interface{}{
    "v": (*T)(nil),
})
if err != nil {
    fmt.Println(err)
}

输出:

gob: gob: cannot encode nil pointer of type *main.T inside interface

这是由未导出的方法生成的 Encoder.encodeInterface()。引用自 encode.go,未导出方法 Encoder.encodeInterface():

// Gobs can encode nil interface values but not typed interface
// values holding nil pointers, since nil pointers point to no value.
elem := iv.Elem()
if elem.Kind() == reflect.Ptr && elem.IsNil() {
    errorf("gob: cannot encode nil pointer of type %s inside interface", iv.Elem().Type())
}

因此您的 Encoder.Encode() 失败了,它没有向其输出(即 bys 缓冲区)写入任何内容,因此尝试从中读取(解码)任何内容都会导致 EOF。

但是为什么不能对包含 nil 指针的 interface{} 值进行编码?引用 encoding/gob 的包文档:

Pointers are not transmitted, but the things they point to are transmitted; that is, the values are flattened.

你的 interface{} 包含一个指针类型的值,但是那个指针是 nil,它指向任何东西,它不能被展平。


github 上有一个相关问题:encoding/gob: panic on encoding nil pointer #3704

拉斯:

gob doesn't know what a pointer is: everything gets flattened. Putting a nil pointer in an interface{} value creates a non-zero value (it's not the nil interface) that gob cannot send (it can't express 'nil pointer').

罗伯·派克:

Correct. An interface value can be transmitted only if the concrete value itself is transmittable. At least for now, that's equivalent to saying that interfaces holding typed nil pointers cannot be sent.