1 回答
TA贡献1851条经验 获得超4个赞
有两个问题,第一个是你给unmarshal
一个指针,然后在unmarshal
自己内部创建另一个指针,所以你最终会传递**Foo
给 gob 解码器。
第二个问题是您interface{}
在函数内获取 'es 的指针。这会以某种方式影响数据的编码方式。如果您将指针传递给函数并且不修改函数内部的变量,那么一切正常。
固定代码如下所示,playground 链接:
type Foo struct {
A string
B string
}
func marshal(i interface{}) ([]byte, error) {
var indexBuffer bytes.Buffer
encoder := gob.NewEncoder(&indexBuffer)
err := encoder.Encode(i)
return indexBuffer.Bytes(), err
}
func unmarshal(data []byte, e interface{}) error {
buf := bytes.NewBuffer(data)
dec := gob.NewDecoder(buf)
err := dec.Decode(e)
fmt.Println("Unmarshal", e)
return err
}
func marshalJ(i interface{}) ([]byte, error) {
return json.Marshal(i)
}
func unmarshalJ(data []byte, e interface{}) error {
return json.Unmarshal(data, e)
}
func main() {
foo := Foo{"Hello", "world!"}
gob.Register(Foo{})
data, err := marshal(&foo)
fmt.Println("got", len(data), err)
var bar Foo
err = unmarshal(data, &bar)
fmt.Println("Main err", err)
fmt.Println("Main", bar)
fmt.Println("-------------------------")
data, err = marshalJ(foo)
fmt.Println("got J", len(data), err)
err = unmarshalJ(data, &bar)
fmt.Println("Main J err", err)
fmt.Println("Main J", bar)
}
编辑:作为对评论的回应。
预防这样的问题有时很困难,我认为问题的根源是使用interface{}它会丢弃类型信息,不幸的是,我们对此无能为力(除了为每种类型制作显式解码器功能)。第二个“问题”是 gob 只是忽略了类型不匹配而没有错误的事实,因此没有给我们任何关于我们做错了什么的迹象。
我们在解码端可以做的是添加更严格的类型检查。我们可以要求解码器将解码后的值放入 a 中interface{},然后检查解码后的类型是否与 的类型匹配e:
type Foo struct {
A string
B string
}
func marshal(i interface{}) ([]byte, error) {
var indexBuffer bytes.Buffer
encoder := gob.NewEncoder(&indexBuffer)
err := encoder.Encode(&i)
return indexBuffer.Bytes(), err
}
func unmarshal(data []byte, e interface{}) (err error) {
buf := bytes.NewBuffer(data)
dec := gob.NewDecoder(buf)
eVal := reflect.ValueOf(e)
eType := eVal.Type()
if eVal.Kind() != reflect.Ptr {
return errors.New("e must be a pointer")
}
var u interface{}
err = dec.Decode(&u)
uVal := reflect.ValueOf(u)
uType := uVal.Type()
if eType.Elem() != uType {
return fmt.Errorf("decoded type '%s' and underlying type of e '%s' not the same", uType.String(), eType.Elem())
}
eVal.Elem().Set(uVal)
return err
}
func main() {
foo := Foo{"Hello", "world!"}
gob.Register(Foo{})
data, err := marshal(foo)
fmt.Println("got", len(data), err)
var bar Foo
var invalid interface{} = bar
err = unmarshal(data, &invalid)
fmt.Println("Main err", err)
fmt.Println("Main", bar)
err = unmarshal(data, &bar)
fmt.Println("Main err", err)
fmt.Println("Main", bar)
}
输出:
got 61 <nil>
Main err decoded type 'main.Foo' and underlying type of e 'interface {}' not the same
Main { }
Main err <nil>
Main {Hello world!}
- 1 回答
- 0 关注
- 89 浏览
添加回答
举报