1

我正在编写一个包装器来映射我需要的一些附加功能。一些最重要的事情是在保持通用性的同时编组和解组数据的能力。我设法使用 encoding/gob 编码器编写了一个编组器,但是如果编组的数据是人类可读的会很好,我决定用 JSON 编写另一个实现。

我通过使用 Register() 将实现对象实例传递给 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 类型的变量时,它说:

恐慌:接口转换:map[string]interface {} 不是 genericValue:缺少方法键编辑:糟糕,实际上它是这样说的!

Error with decoding! json: cannot unmarshal object into Go value of genericValue

很明显,它试图像这里所说的那样编组数据:http: //blog.golang.org/json-and-go(参见“带有接口的通用 JSON{}”)

我怎样才能让它尝试将数据适合特定的实现,例如如果实现是 Register()ed,gob 解码器会尝试?Register() 是天赐之物,它允许编组和解组,就像它什么都不是一样。如何让 JSON 做同样的事情?

4

2 回答 2

2

如果您的类型实现了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。

于 2014-03-25T16:59:30.880 回答
0

好啦,终于开工啦。这个问题提供了答案。为什么 json.Unmarshal 返回一个映射而不是预期的结构?

“你已经向 json 传递了一个指向抽象接口的指针。你应该简单地将一个指针作为抽象接口传递给 Ping”——这也适用于我的情况。(出于某种原因,指向抽象接口的指针对于 gob 包来说就足够了。看来我必须研究 Go 接口和反射才能理解为什么......)

如果有人有更好的答案,我仍然不会将此标记为已解决的问题。

于 2014-03-23T22:14:44.150 回答