Reputation: 425
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
Upvotes: 1
Views: 2760
Reputation: 418297
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.
Upvotes: 5