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

时间:2018-07-19 12:08:48

标签: json go reflection

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

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

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

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

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

保存数据。如何定义该类型以便json解组器动态转换为正确的类型?在这种情况下,“ 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)
}

1 个答案:

答案 0 :(得分:1)

您应该使用json.RawMessage动态解组数据。

您可以将Gift's 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