包装gob解码器

我将加密的 gobs 存储在 kv 数据库中,并希望在带有密钥和接口的包中具有便利功能,它解密存储的值,将其解码为传递的接口,并且消费者代码可以在没有了解有关正在存储的数据的任何信息。


当它与 json 编码器一起工作时,我无法弄清楚为什么我无法使用 gob 写入指针值。简化后的代码如下所示:


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)

}

(播放链接)


unmarshalJ 的行为与我预期的一样,即在 Main 中,我的 bar 变量是 foo 的副本,因为 unmarshalJ 接收到指向 bar 的指针并将其传递。


另一方面,unmarshal 函数在本地更改了参数,但并未对 Main 中的栏进行更改。gob.Decode 在内部传递了 reflect.ValueOf,我一直试图避免使用反射,所以我不太明白它的作用。


我的两个问题是:

  1. 是否可以像我想要的那样拥有一个包装器,并像使用 json 编码器一样更改调用者的值?

  2. 更多的奖励问题,因为这让我觉得我没有完全掌握 go 中的指针:如何更改 unmarshal.e 的值,但当 unmarshal.e 是指向 Main.bar 的指针时不会更改 Main.bar?在这里让我感到困惑的另一件事是,在 unmarshal 内部,我必须将 &e 传递给 Decode ,否则它会以want struct type main.Foo; got non-struct.


收到一只叮咚
浏览 90回答 1
1回答

繁花不似锦

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

相关分类

Go