json - 在读取 json 数据时动态识别对象的类型

标签 json go reflection

很新,很抱歉,如果这个问题听起来很明显。

我想在读取 json 文件时使用反射来识别对象的类型。

用例(请参阅下面的代码)如下:我有两个包含不同字段的结构 BoyGift 和 GirlGift。我还有一个 bool 指示符 IsBoy,如果礼物的接收者是男孩,则该指示符为 true,否则为 false。

封装此行为的类型是 Gift 类型:

//Gift type
type Gift struct {
    IsBoy   bool     `json:"isBoy"`
    Payload ??? `json:"payload"`
}

保存数据。我如何定义该类型以便 json 解码动态转换为正确的类型?本例中的“json 模式”定义了 Gift 应该是 BoyGift 或 GirlGift。是否可以通过反射来做到这一点?如何?

如果 bool 信息已知,那么进行两次解码会很棒

package main

import (
    "encoding/json"
    "fmt"
)

//BoyGift type
type BoyGift struct {
    Cars  uint32 `json:"cars"`
    Balls uint32 `json:"balls"`
}

//GirlGift type
type GirlGift struct {
    Dolls uint32 `json:"dolls"`
    Lego  uint32 `json:"lego"`
}

//Gift type
type Gift struct {
    IsBoy   bool     `json:"isBoy"`
    Payload GirlGift `json:"payload"`
}

func main() {

    b := []byte(`{
        "isBoy": true,
        "payload": {
          "cars": 1,
          "balls": 2
        }
      }`)

    var g Gift
    err := json.Unmarshal(b, &g)

    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(g)
}

最佳答案

你应该使用 json.RawMessage动态解码您的数据。

您可以将 Gift 的 Payliad 定义为 json.RawMessage,然后延迟解码,直到您知道 IsBoy 的值。您可以在下面找到有关如何操作的基本示例。

package main

import (
    "encoding/json"
    "fmt"
)

//BoyGift type
type BoyGift struct {
    Cars  uint32 `json:"cars"`
    Balls uint32 `json:"balls"`
}

//GirlGift type
type GirlGift struct {
    Dolls uint32 `json:"dolls"`
    Lego  uint32 `json:"lego"`
}

//Gift type
type Gift struct {
    IsBoy   bool            `json:"isBoy"`
    Payload json.RawMessage `json:"payload"`
}

func main() {

    b1 := []byte(`{
        "isBoy": true,
        "payload": {
          "cars": 1,
          "balls": 2
        }
      }`)

    b2 := []byte(`{
        "isBoy": false,
        "payload": {
          "dolls": 3,
          "lego": 4
        }
      }`)

    for _, b := range [][]byte{b1, b2} {
        var g Gift

        err := json.Unmarshal(b, &g)
        if err != nil {
            fmt.Println(err)
            return
        }

        if g.IsBoy {
            var boyGift BoyGift
            err := json.Unmarshal(g.Payload, &boyGift)
            if err != nil {
                fmt.Println(err)
                return
            }
            fmt.Println(boyGift)

        } else {
            var girlGift GirlGift
            err := json.Unmarshal(g.Payload, &girlGift)
            if err != nil {
                fmt.Println(err)
                return
            }
            fmt.Println(girlGift)

        }
    }

}

如果您想将Payload用作接口(interface){}(可以是BoyGiftGirlGift) ,您可以为解码创建额外的辅助结构。查看 Go Playground 中的扩展示例:https://play.golang.org/p/q1Hn45bgjsc

关于json - 在读取 json 数据时动态识别对象的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51422333/

相关文章:

json - 使用 JQ 的多个过滤器

python - 如何使用 Google API 获取 youtube-v3-discoverydocument.json?

javascript - 试图找出如何重新格式化 JSON 响应并重新格式化数据

postgresql - 引擎盖 "config.json"值

没有限定名称的Java反射

javascript - 来自 $.ajax 和 json 的数据对象是浅层的

json - Go:在json响应中从数据库复制各种类型的数据

跨并行 goroutine 共享 channel 时的 Golang 竞争条件

java - 重新创建方法调用(使用反射)

java - 出于测试目的使用反射来迭代成员是否合适?