我正在编写一个包装器来映射一些我需要的附加功能。一些最重要的事情是在保持通用性的同时编码和解码数据的能力。我设法使用 encoding/gob 编码器编写了一个编码器,但是如果编码的数据是人类可读的就更好了,我决定用 JSON 编写另一个实现。
通过使用 Register() 向通用接口(interface)变量传递一个实现对象实例,我得到了从通用接口(interface)变量编码和解码的 gob。 (此资源帮助我了解了详细信息!http://www.funcmain.com/gob_encoding_an_interface)
但是,JSON 没有 Register()。假设我们有一个类型的值
type ConcreteImplementation struct {
FieldA string
FieldB string
}
func (c ConcreteImplementation) Key() string {
return c.FieldA // ConcreteImplementation implements genericValue
}
在类型变量中
type genericValue interface {
Key() string
}
当我整理它时,它会像这样输出 JSON:
{"FieldA":"foo","FieldB":"bar"}
当我尝试将其再次解码为 genericValue 类型的变量时,它说:
panic :接口(interface)转换:map[string]interface {} 不是 genericValue:缺少方法键 编辑:糟糕,实际上它是这样说的!
Error with decoding! json: cannot unmarshal object into Go value of genericValue
很明显,它会尝试像此处所说的那样编码数据:http://blog.golang.org/json-and-go (参见“带接口(interface)的通用 JSON{}”)
我怎样才能让它尝试使数据适合特定的实现,比如如果实现是 Register()ed,gob 解码器会尝试? Register() 是天赐之物,它允许一般地编码和解码,就像它什么都不是。如何让 JSON 执行相同的操作?
最佳答案
如果您的类型实现了 Unmarshaler 会怎么样? ?
或此处相同的代码:
type ConcreteImplementation struct {
FieldA string
FieldB string
}
func (c ConcreteImplementation) Key() string {
return c.FieldA // ConcreteImplementation implements genericValue
}
// implementing json.Unmarshaler
func (c *ConcreteImplementation) UnmarshalJSON(j []byte) error {
m := make(map[string]string)
err := json.Unmarshal(j, &m)
if err != nil {
return err
}
if v, ok := m["FieldA"]; ok {
c.FieldA = v
}
if v, ok := m["FieldB"]; ok {
c.FieldB = v
}
return nil
}
type genericValue interface {
Key() string
json.Unmarshaler
}
func decode(jsonStr []byte, v genericValue) error {
return json.Unmarshal(jsonStr, v)
}
有了它,您可以将 genericValue 传递给 json.Unmarshal。
关于json - 在匹配 Go 中的底层类型时将 JSON 解码为接口(interface)变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22596260/