英文:
De- and encode interface{} with Gob
问题
我正在尝试对包含Interface{}字段的结构进行解码和编码。
问题在于,编码工作正常,但是如果我尝试将数据解码到data
,值会变成{ <nil>}
。
如果我将Data interface{}
更改为Data substring
,它实际上是有效的,但对我来说这不是一个解决方案,因为我想要缓存对数据库的查询结果,这些结果根据查询的不同具有不同的类型(例如Users
或Cookies
)。
#最小工作示例
##源代码
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() {
// 编码
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())
// 解码
var data Data
pCache := bytes.NewBuffer(mCache.Bytes())
decCache := gob.NewDecoder(pCache)
decCache.Decode(&data)
fmt.Printf("Decoded: ")
fmt.Println(data)
}
##输出
###预期输出
Encoded: [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 131 3 1 1 7 83 117 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]
Decoded: {FooBar {Test}}
###当前结果
Encoded: [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 131 3 1 1 7 83 117 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]
Decoded: { <nil>}
英文:
I'm trying to de- and encode a struct which contains a Interface{} as field.
The problem there is, that the encoding works fine, but if I try to decode the data to data
the value gets { <nil>}
.
It actually works, if I change Data interface{}
to Data substring
, but this is not a solution for me because I want to cache the results of a query to a database which have different types depending on the query. (e.g. Users
or Cookies
)
#Minimal working example
Source
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)
}
##Outputs
###Expected output
Encoded: [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 131 3 1 1 7 83 117 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]
Decoded: {FooBar {Test}}
###Current Result
Encoded: [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 131 3 1 1 7 83 117 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]
Decoded: { <nil>}
答案1
得分: 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
英文:
The problem is that in your code, there is an error when executing encCache.Encode(encodeData)
but since you don't check for error, you don't realize that. The output is blank because encodedData fails to get encoded properly.
If you add error checking,
err := enc.Encode(encodeData)
if err != nil {
log.Fatal("encode error:", err)
}
Then you'd see something like
2013/03/09 17:57:23 encode error:gob: type not registered for interface: main.SubType
If you add one line to your original code before enc.Encode(encodeData),
gob.Register(SubType{})
Then you get expected output.
Decoded: {FooBar {Test}}
答案2
得分: -7
你不能将解码结果转换为接口,因为解码器无法确定字段的类型。
你可以用几种不同的方式来处理这个问题。一种方式是让Data持有一个包含每种可能被解码的类型的字段的结构体。但是这种类型可能非常复杂。
另一种方式是为你的结构体实现GobDecoder和GobEncoder接口,并为这些类型实现自己的序列化。不过这可能不是最理想的方式。
也许最好的方法是让缓存存储特定的类型,并为每种类型使用单独的方法。以你的例子为例,你的应用程序可以在缓存上有一个名为GetSubType(key string) (*SubType, error)
的方法。它会返回具体的类型或解码错误,而不是一个接口。这样做会更清晰、更易读,也更类型安全。
英文:
You can't decode into an interface because the decoder has no way to determine what type the field should be.
You can handle this in a few different ways. One is to have Data hold a struct with a field for every type that could be decoded. But the type could be very complicated.
The other way is to implement the GobDecoder and GobEncoder interface for your struct and implement your own serialization for the types. This is probably not ideal though.
Perhaps the best approach is to have the cache store specific types instead and use separate method for each type. To use your example. Your application would have a cache method called GetSubType(key string) (*SubType, error)
on the cache. This would return the concrete type or a decoding error instead of an interface. It would be cleaner and more readable as well as more typesafe.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论