假设我有一条如下所示的 JSON 消息:
{
"type": string
"data": list of something that is based on above type
}
可能有两个例子
{
"type": "car"
"data": [{"color": "red", "mpg": 16.4}]
}
和
{
"type": "house"
"data": [{"color": "blue", "state": "CA"}]
}
我想定义一个结构体,这样我基本上只能解码类型,然后使用它来正确地解组数据字段。我尝试了以下
type message struct {
Type string `json:"type"`
Data []byte `json:"data"`
}
type car struct {
Color string
MPG float64
}
type house struct {
Color string
State string
}
错误地认为它只会让数据字段保持原始状态,以便我稍后将其解组到
car
或 house
结构中。我知道我可以将 Data 定义为 []interface{}
并做一些其他工作来获得我想要的,但我想知道这是否是(目前)Go 中最好的方法?如果出现这种情况,假设我无法更改 JSON 定义 - 我只是这里服务的使用者。
json.RawMessage
的完美用例。查看那里的 Unmarshal
示例。
对于您的示例,这看起来像:
type message struct {
Type string `json:"type"`
Data []json.RawMessage `json:"data"`
}
type car struct {
Color string
MPG float64
}
type house struct {
Color string
State string
}
func main() {
if err := parseAndPrint(carJSON); err != nil {
panic(err)
}
if err := parseAndPrint(houseJSON); err != nil {
panic(err)
}
}
func parseAndPrint(b []byte) error {
msg := new(message)
if err := json.Unmarshal(b, msg); err != nil {
panic(err)
}
switch msg.Type {
case "car":
for _, data := range msg.Data {
c := new(car)
if err := json.Unmarshal(data, c); err != nil {
return err
}
fmt.Println(c)
}
case "house":
for _, data := range msg.Data {
h := new(house)
if err := json.Unmarshal(data, h); err != nil {
return err
}
fmt.Println(h)
}
}
return nil
}
// Tucked here to get out of the way of the example
var carJSON = []byte(`
{
"type": "car",
"data": [{"color": "red", "mpg": 16.4}]
}
`)
var houseJSON = []byte(`{
"type": "house",
"data": [{"color": "blue", "state": "CA"}]
}
`)
现在您对解析结果的处理方式取决于您和您的程序的需求。在边缘解析并仅传递完整类型的消息,向外部结构体添加
Parsed any
字段等