简体   繁体   中英

gob attempting to decode nil value results in EOF error

I need to use the gob to encode some data, however, I find that "type nil" can not be processed correctly (go 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
}

Output:

panic: EOF

You are swallowing an error returned by Encoder.Encode() :

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

Output:

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

This is generated by unexported method Encoder.encodeInterface() . Quoting from encode.go , unexported method 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())
}

So your Encoder.Encode() fails, it writes nothing to its output (which is the bys buffer), so attempting to read (decode) anything from it results in EOF.

But why can't you encode an interface{} value holding a nil pointer? Quoting from the package doc of encoding/gob :

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

Your interface{} contains a value of pointer type, but that pointer is nil , it points to nothing, it cannot be flattened.


Here is a related issue on github: encoding/gob: panic on encoding nil pointer #3704

Russ:

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').

Rob Pike:

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM