How to unmarshal JSON into interface{} in Go?

2020-01-31 00:28发布

I'm a newbie in Go and now I have a problem. I have a type called Message, it is a struct like this:

type Message struct {
    Cmd string `json:"cmd"`
    Data interface{} `json:"data"`
}

I also have a type called CreateMessage like this:

type CreateMessage struct {
    Conf map[string]int `json:"conf"`
    Info map[string]int `json:"info"`
}

And I have a JSON string like {"cmd":"create","data":{"conf":{"a":1},"info":{"b":2}}}.

When I use json.Unmarshal to decode that into a Message variable, the answer is {Cmd:create Data:map[conf:map[a:1] info:map[b:2]]}.

So could I decode the JSON into a Message struct and change its Data's interface{} to type CreateMessage according to the Cmd?

I tried to convert Data directly into type CreateMessage but the complier told me that Data is a map[sting]interface{} type.

标签: json go
1条回答
家丑人穷心不美
2楼-- · 2020-01-31 00:56

Define a struct type for the fixed part of the message with a json.RawMessage field to capture the variant part of the message. Define struct types for each of the variant types and decode to them based on the the command.

type Message struct {
  Cmd string `json:"cmd"`
  Data      json.RawMessage
}  

type CreateMessage struct {
    Conf map[string]int `json:"conf"`
    Info map[string]int `json:"info"`
}  

func main() {
    var m Message
    if err := json.Unmarshal(data, &m); err != nil {
        log.Fatal(err)
    }
    switch m.Cmd {
    case "create":
        var cm CreateMessage
        if err := json.Unmarshal([]byte(m.Data), &cm); err != nil {
            log.Fatal(err)
        }
        fmt.Println(m.Cmd, cm.Conf, cm.Info)
    default:
        log.Fatal("bad command")
    }
}

playground example

查看更多
登录 后发表回答