代码之家  ›  专栏  ›  技术社区  ›  Timmmm

在Go中解组JSON标记的union

  •  0
  • Timmmm  · 技术社区  · 5 年前

    我正在尝试解Marshal的JSON请求 Google Actions . 它们具有如下标记的联合数组:

    {
        "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        "inputs": [{
          "intent": "action.devices.QUERY",
          "payload": {
            "devices": [{
              "id": "123",
              "customData": {
                "fooValue": 74,
                "barValue": true,
                "bazValue": "foo"
              }
            }, {
              "id": "456",
              "customData": {
                "fooValue": 12,
                "barValue": false,
                "bazValue": "bar"
              }
            }]
          }
        }]
    }
    
    {
        "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
        "inputs": [{
          "intent": "action.devices.EXECUTE",
          "payload": {
            "commands": [{
              "devices": [{
                "id": "123",
                "customData": {
                  "fooValue": 74,
                  "barValue": true,
                  "bazValue": "sheepdip"
                }
              }, {
                "id": "456",
                "customData": {
                  "fooValue": 36,
                  "barValue": false,
                  "bazValue": "moarsheep"
                }
              }],
              "execution": [{
                "command": "action.devices.commands.OnOff",
                "params": {
                  "on": true
                }
              }]
            }]
          }
        }]
    }
    
    etc.
    

    很明显,我可以把这件事告诉 interface{} 并使用完全动态的类型转换和所有东西对其进行解码,但Go对结构的解码有很好的支持。有没有办法在围棋中优雅地做到这一点( like you can in Rust 例如)?

    我觉得你可以通过阅读demarshalling一开始的内容来做到这一点:

    type Request struct {
        RequestId string
        Inputs    []struct {
            Intent   string
            Payload  interface{}
        }
    }
    

    然而,一旦您拥有 Payload interface{} 似乎没有任何方法将其反序列化为 struct (除了序列化和反序列化之外,这很糟糕。有什么好的解决方案吗?

    0 回复  |  直到 5 年前
        1
  •  6
  •   Iain Duncan pujaji    5 年前

    而不是解组 Payload interface{} 您可以将其存储为 json.RawMessage 然后根据意图的价值对其进行解组。json文档中的示例显示了这一点:

    https://golang.org/pkg/encoding/json/#example_RawMessage_unmarshal

    将该示例与JSON和struct结合使用,您的代码如下所示:

    type Request struct {
        RequestId string
        Inputs    []struct {
            Intent   string
            Payload  json.RawMessage
        }
    }
    
    var request Request
    err := json.Unmarshal(j, &request)
    if err != nil {
        log.Fatalln("error:", err)
    }
    for _, input := range request.Inputs {
        var payload interface{}
        switch input.Intent {
        case "action.devices.EXECUTE":
            payload = new(Execute)
        case "action.devices.QUERY":
            payload = new(Query)
        }
        err := json.Unmarshal(input.Payload, payload)
        if err != nil {
            log.Fatalln("error:", err)
        }
        // Do stuff with payload
    }