登录
首页 >  Golang >  Go问答

最佳的 Golang JSON 动态解组方法

来源:stackoverflow

时间:2024-02-13 10:39:25 221浏览 收藏

从现在开始,努力学习吧!本文《最佳的 Golang JSON 动态解组方法》主要讲解了等等相关知识点,我会在golang学习网中持续更新相关的系列文章,欢迎大家关注并积极留言建议。下面就先一起来看一下本篇正文内容吧,希望能帮到你!

问题内容

使用 golang,我需要解组具有有限数量的结构和公共头的嵌套 json 消息。标头包含类型信息,用于标识 json 消息包含哪些详细结构。我尝试做的是从头部提取类型信息,然后动态选择细节的结构。程式化示例 json 字符串如下所示:

{"type":"a_number", "data":{"somenumber":1234}}
{"type":"b_string", "data":{"somestring":"a string", "anotherstring": "a second string"}}`

我最初的方法是使用如下结构:

type head struct {
    type  string `json:"type"`
    data interface{} `json:"data"`
}

type a struct {
    somenumber decimal.decimal `json:"somenumber"`
}

type b struct {
    somestring string `json:"somestring"`
    anotherstring string `json:"anotherstring"`
}

我尝试在数据元素上使用接口。(类型)来检查哪个结构适用,如下所示:

var msg head

json.unmarshal([]byte(jsonstring), &msg)

switch v := msg.data.(type) {
    case a:
        fmt.printf("type is a (%v)", v)
        detail := msg.data.(a)
        fmt.println(detail.somenumber)
    case b:
        fmt.printf("type is b (%v)", v)
        detail := msg.data.(b)
        fmt.println(detail.somestring)
    default:
        fmt.printf("i don't know about type %t!\n", v)
}

这显然不起作用,因为 msg 的类型是 map[string]interface {}。我的下一次尝试是使用类似的东西:

data := msg.data.(map[string]interface {})

v ,exist := data["somestring"]
if exist {
    fmt.println("somestring: ",v)
}

在这个简单的情况下,这是可行的,但在实际情况下,有两个以上的结构,而且它们本身是嵌套的并且相当复杂。

我设法找到的唯一方法是创建多个特定结构并使用多个解组,如下所示:

type generichead struct {
    type  string `json:"type"`
    data interface{} `json:"data"`
}

type a struct {
    somenumber decimal.decimal `json:"somenumber"`
}

type b struct {
    somestring string `json:"somestring"`
    anotherstring string `json:"anotherstring"`
}

type specifica struct {
    type  string `json:"type"`
    data a `json:"data"`
}

type specificb struct {
    type  string `json:"type"`
    data b `json:"data"`
}

然后

var msg Head

json.Unmarshal([]byte(jsonString), &msg)

if msg.Type == "a_number" {
   var data SpecificA
   json.Unmarshal([]byte(jsonString), &data)
} else {
   var data SpecificA
   json.Unmarshal([]byte(jsonString), &data)
}

必须定义多个(冗余)结构并多次解组似乎非常低效且不必要的复杂。

解决这种情况的更有效的“最佳实践”方法是什么?


正确答案


感谢 cerise limón 的指点,Decoding generic JSON objects to one of many formats 中已经提供了答案,并使用 json.rawmessage 作为解决方案:

type head struct {
    type  string `json:"type"`
    data json.rawmessage `json:"data"`
}

var msg Head

json.Unmarshal([]byte(jsonString), &msg)

switch msg.Type {
    case "a_number":
        var detail A
        json.Unmarshal([]byte(msg.Data),&detail)
        fmt.Println(detail.SomeNumber)
    case "b_string":
        var detail B
        json.Unmarshal([]byte(msg.Data),&detail)
        fmt.Println(detail.SomeString)
    default:
        fmt.Printf("I don't know about type %s!\n",  msg.Type)
}

以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于Golang的相关知识,也可关注golang学习网公众号。

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>