登录
首页 >  Golang >  Go问答

解码部分json消息,并据此确定其余部分的类型

来源:stackoverflow

时间:2024-04-05 23:03:37 233浏览 收藏

在IT行业这个发展更新速度很快的行业,只有不停止的学习,才不会被行业所淘汰。如果你是Golang学习者,那么本文《解码部分json消息,并据此确定其余部分的类型》就很适合你!本篇内容主要包括##content_title##,希望对大家的知识积累有所帮助,助力实战开发!

问题内容

我收到一条消息,例如

type message struct {
    Type   string       `json:"type"`
    Data   interface{}  `json:"data"`
}

数据类型取决于类型。简而言之,我想从消息中获取 type,对其进行切换,并根据 json.unmarshal(data) 的结果转换为特定的结构。但事实并非如此,因为当我 unmarshal 这条消息时,data 立即变成一个 map[string] 接口,然后我不能再正常地将它变成一个结构(好吧,我要么必须 unmarshal 2 次)。如何妥善解决这个问题?


正确答案


然后进行两阶段解码——利用 encoding/json 有一个特殊类型 rawmessage 的事实,其语义“只需按原样保存表示该值的字节序列”:

package main

import (
    "encoding/json"
    "fmt"
)

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

type a struct {
    foo string
    bar string
}

type b struct {
    quux  int
    blorb []int
}

func decodemessage(b []byte) (interface{}, error) {
    var m message
    err := json.unmarshal(b, &m)
    if err != nil {
        return nil, err
    }

    switch m.type {
    case "a":
        var a a
        err = json.unmarshal(m.data, &a)
        if err != nil {
            return nil, err
        }
        return a, nil
    case "b":
        var b b
        err = json.unmarshal(m.data, &b)
        if err != nil {
            return nil, err
        }
        return b, nil
    }
    return nil, fmt.errorf("cannot handle type: %s", m.type)
}

const msga = `{
  "type": "a",
  "data": {
    "foo": "xyzzy",
    "bar": "r0xx0rz"
  }
}`

const msgb = `{
  "type": "b",
  "data": {
    "quux": 42,
    "blorb": [1, 2, 3, 4]
  }
}`

const msgx = `{
  "type": "x",
  "data": null
}`

func main() {
    for _, s := range []string{msga, msgb, msgx} {
        d, err := decodemessage([]byte(s))
        fmt.println(d, err)
    }
}

Playground

另一个有点不同的变体:

package main

import (
    "encoding/json"
    "fmt"
)

type message struct {
    Type string          `json:"type"`
    Data json.RawMessage `json:"data"`
}

type A struct {
    Foo string
    Bar string
}

type B struct {
    Quux  int
    Blorb []int
}

func decodeMessage(b []byte) (interface{}, error) {
    var m message
    err := json.Unmarshal(b, &m)
    if err != nil {
        return nil, err
    }

    var v interface{}
    switch m.Type {
    case "a":
        v = &A{}
    case "b":
        v = &B{}
    default:
        return nil, fmt.Errorf("cannot handle type: %s", m.Type)
    }

    err = json.Unmarshal(m.Data, v)
    if err != nil {
        return nil, err
    }
    return v, nil
}

const msgA = `{
  "type": "a",
  "data": {
    "Foo": "xyzzy",
    "Bar": "r0xx0rz"
  }
}`

const msgB = `{
  "type": "b",
  "data": {
    "Quux": 42,
    "Blorb": [1, 2, 3, 4]
  }
}`

const msgX = `{
  "type": "x",
  "data": null
}`

func main() {
    for _, s := range []string{msgA, msgB, msgX} {
        d, err := decodeMessage([]byte(s))
        fmt.Println(d, err)
    }
}

Playground

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

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