首页 > 解决方案 > 读取json数据时动态识别对象类型

问题描述

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

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

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

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

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

保存数据。如何定义该类型以使 json unmarshal 动态转换为正确的类型?在这种情况下,“json 模式”定义了 Gift 应该是 BoyGift 或 GirlGift。是否可以通过反射来做到这一点?如何?

如果布尔信息已知,则进行两次解组会很棒

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)
}

标签: jsongoreflection

解决方案


您应该使用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{}(可以是BoyGiftor GirlGift),您可以创建额外的辅助结构来进行解组。检查 Go Playground 中的扩展示例:https: //play.golang.org/p/q1Hn45bgjsc


推荐阅读