1 回答

TA貢獻1851條經(jīng)驗 獲得超4個贊
有兩個問題,第一個是你給unmarshal
一個指針,然后在unmarshal
自己內(nèi)部創(chuàng)建另一個指針,所以你最終會傳遞**Foo
給 gob 解碼器。
第二個問題是您interface{}
在函數(shù)內(nèi)獲取 'es 的指針。這會以某種方式影響數(shù)據(jù)的編碼方式。如果您將指針傳遞給函數(shù)并且不修改函數(shù)內(nèi)部的變量,那么一切正常。
固定代碼如下所示,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 只是忽略了類型不匹配而沒有錯誤的事實,因此沒有給我們?nèi)魏侮P于我們做錯了什么的跡象。
我們在解碼端可以做的是添加更嚴格的類型檢查。我們可以要求解碼器將解碼后的值放入 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 關注
- 124 瀏覽
添加回答
舉報