18

我正在尝试对包含 Interface{} 作为字段的结构进行解码和编码。

存在的问题是,编码工作正常,但如果我尝试将数据解码为data值 get { <nil>}

如果我更改Data interface{}为,它实际上可以工作,Data substring但这对我来说不是解决方案,因为我想将查询结果缓存到根据查询具有不同类型的数据库中。(例如UsersCookies

最小的工作示例

来源

http://play.golang.org/p/aX7MIfqrWl

package main

import (
    "bytes"
    "encoding/gob"
    "fmt"
)

type Data struct {
    Name string
    Data interface{}
}

type SubType struct {
    Foo string
}

func main() {
    // Encode
    encodeData := Data{
        Name: "FooBar",
        Data: SubType{Foo: "Test"},
    }
    mCache := new(bytes.Buffer)
    encCache := gob.NewEncoder(mCache)
    encCache.Encode(encodeData)

    fmt.Printf("Encoded: ")
    fmt.Println(mCache.Bytes())

    // Decode
    var data Data
    pCache := bytes.NewBuffer(mCache.Bytes())
    decCache := gob.NewDecoder(pCache)
    decCache.Decode(&data)

    fmt.Printf("Decoded: ")
    fmt.Println(data)
}

输出

预期产出

编码: [37 255 129 3 1 1 4 68 97 116 97 1 255 130 0 1 2 1 4 78 97 109 101 1 12 0 1 4 68 97 116 97 1 255 132 0 0 0 29 255 781 3 7 1 1 98 84 121 112 101 1 255 132 0 1 1 1 3 70 111 111 1 12 0 0 0 19 255 130 1 6 70 111 111 66 97 114 1 1 4 84 101 115 116 0 0]

解码:{FooBar {Test}}

当前结果

编码: [37 255 129 3 1 1 4 68 97 116 97 1 255 130 0 1 2 1 4 78 97 109 101 1 12 0 1 4 68 97 116 97 1 255 132 0 0 0 29 255 781 3 7 1 1 98 84 121 112 101 1 255 132 0 1 1 1 3 70 111 111 1 12 0 0 0 19 255 130 1 6 70 111 111 66 97 114 1 1 4 84 101 115 116 0 0]

解码:{}

4

2 回答 2

44

问题是在您的代码中,执行时出现错误,encCache.Encode(encodeData)但由于您不检查错误,因此您没有意识到这一点。输出为空白,因为 encodedData 未能正确编码。

如果添加错误检查,

err := enc.Encode(encodeData)
if err != nil {
    log.Fatal("encode error:", err)
}

然后你会看到类似的东西

2013/03/09 17:57:23 encode error:gob: type not registered for interface: main.SubType

如果在 enc.Encode(encodeData) 之前在原始代码中添加一行,

gob.Register(SubType{})

然后你得到预期的输出。

Decoded: {FooBar {Test}}

http://play.golang.org/p/xt4zNyPZ2W

于 2013-03-09T23:06:01.150 回答
-6

您无法解码为接口,因为解码器无法确定该字段应该是什么类型。

您可以通过几种不同的方式处理此问题。一种是让 Data 保存一个结构,其中包含可以解码的每种类型的字段。但是类型可能非常复杂。

另一种方法是为您的结构实现 GobDecoder 和 GobEncoder 接口,并为类型实现您自己的序列化。不过,这可能并不理想。

也许最好的方法是让缓存存储特定类型,并为每种类型使用单独的方法。用你的例子。您的应用程序将在缓存GetSubType(key string) (*SubType, error)上调用一个缓存方法。这将返回具体类型或解码错误而不是接口。它会更干净,更易读,也更安全。

于 2013-01-02T19:05:53.247 回答