【发布时间】:2017-07-31 23:54:01
【问题描述】:
我有一些 JSON 格式:
[{
"type": "car",
"color": "red",
"hp": 85,
"doors": 4
}, {
"type": "plane",
"color": "blue",
"engines": 3
}]
我有满足车辆接口的car 和plane 类型;我希望能够写:
var v []vehicle
e := json.Unmarshal(myJSON, &v)
...让 JSON 用汽车和飞机填充我的车辆部分;相反(不出所料)我只是得到“无法将对象解组为 main.vehicle 类型的 Go 值”。
作为参考,以下是所涉及类型的合适定义:
type vehicle interface {
vehicle()
}
type car struct {
Type string
Color string
HP int
Doors int
}
func (car) vehicle() { return }
type plane struct {
Type string
Color string
Engines int
}
func (plane) vehicle() { return }
var _ vehicle = (*car)(nil)
var _ vehicle = (*plane)(nil)
(请注意,我实际上对 car 和 plane 上的 t 字段完全不感兴趣 - 它可以省略,因为如果有人成功回答了这个问题,这些信息将隐含在v 中的对象。)
有没有办法让 JSON umarhsaller 根据正在解码的数据的某些部分内容(在本例中为类型字段)选择要使用的类型?
(请注意,这不是与Unmarshal JSON with unknown fields 的重复,因为我希望切片中的每个项目都具有不同的动态类型,并且从我知道的'type'属性的值确切地期望什么字段——我只是不知道如何告诉 json.Unmarshal 如何将 'type' 属性值映射到 Go 类型。)
【问题讨论】:
-
是的,你可以实现
json.Unamrshaler,但这取决于你希望你的最终数据结构是什么样子。你对vehicle的期望究竟是什么? -
如问题所示,我希望我的最终数据结构
v的类型为[]vehicle(或[]*vehicle,也可以),其中v[0]是@ 987654338@ 和v[1]是一架飞机。 -
@JimB:你能不重复这个问题吗?我相信我已经充分澄清以证明它不是Unmarshal JSON with unknown fields 的“完全重复”。
-
我看不出这与其他多次被问到的情况有何不同。基本答案始终是对链接副本的建议的组合。您可以解组为通用结构并手动复制字段,或者您可以只读取“类型”字段并将对象再次解组为特定类型。是实现 json.Unmarshaler,还是实现从
[]json.RawMessage{}转换为[]vehicle的函数取决于您,但这将是一个多步骤的过程,您需要实现。 -
嗯,一个问题是我无法在车辆上定义 UnmarshalJSON 方法,因为它是一个接口。我可以使用单个匿名车辆字段创建包装器结构并在其中定义 UnmarhsalJSON(这可行),但最终我得到了一个 []vehicleWrapper 而不是 []vehicle,这不是我想要的。