drfkl66684 2019-05-05 18:05
浏览 31
已采纳

在Go中解组JSON标记的联合

I'm trying to demarshal the JSON requests of Google Actions. These have arrays of tagged unions like this:

{
    "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.

Obviously I can demarshal this to an interface{} and use fully dynamic type casts and everything to decode it, but Go has decent support for decoding to structs. Is there a way to do this elegantly in Go (like you can in Rust for example)?

I feel like you could almost do it by reading demarshalling to this initially:

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

However once you have the Payload interface{} there doesn't seem to be any way to deserialise that into a struct (other than serialising it and deserialising it again which sucks. Is there any good solution?

  • 写回答

1条回答 默认 最新

  • doubengman2072 2019-05-05 18:52
    关注

    Instead of unmarshaling Payload to an interface{} you can store it as a json.RawMessage and then unmarshal it based on the value of Intent. This is shown in the example in the json docs:

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

    Using that example with your JSON and struct your code becomes something like this:

    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
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 python点云生成mesh精度不够怎么办
  • ¥15 QT C++ 鼠标键盘通信
  • ¥15 改进Yolov8时添加的注意力模块在task.py里检测不到
  • ¥50 高维数据处理方法求指导
  • ¥100 数字取证课程 关于FAT文件系统的操作
  • ¥15 如何使用js实现打印时每页设置统一的标题
  • ¥15 安装TIA PortalV15.1报错
  • ¥15 能把水桶搬到饮水机的机械设计
  • ¥15 Android Studio中如何把H5逻辑放在Assets 文件夹中以实现将h5代码打包为apk
  • ¥15 使用小程序wx.createWebAudioContext()开发节拍器