为了账号安全,请及时绑定邮箱和手机立即绑定

为什么要去 json.Unmarshal auto convert interface{}

为什么要去 json.Unmarshal auto convert interface{}

Go
牧羊人nacy 2023-06-12 15:26:37
程序会收到很多 msg,msg 有不同的结构“Data”,所以我定义了 Msg 结构:type Msg struct {    MsgType int    Data interface{}}type Data1 struct {//msg type 1 Data struct}type Data2 struct {//msg type 2 Data struct}func (msgStr string) {    msg := Msg{}    if err := json.Unmarshal([]byte(msgStr), &msg); err != nil {        //log err    }    switch msg.MsgType{    case 1:        //convert msg.Data to a type 1 struct    case 2:        //convert msg.Data to a type 2 struct    }}但是打印出 msg.Data,它是一个映射,而不是 interface{},所以当我通过 msg.Data.(Data1) 将它转换为 Data1 时,出现错误。那么,1. 为什么 interface{} 自动转换为 map?2.如何转换成我想要的Data1结构?3.这个场景的最佳实践是什么。
查看完整描述

1 回答

?
翻阅古今

TA贡献1780条经验 获得超5个赞

1. 因为它看到一个 JSON 对象,并且如文档所述,map[string]interface{}当存储到一个 JSON 对象时变成一个interface{}(这是一般情况下可以保存 JSON 对象中任何内容的唯一类型)。


2. 鉴于您目前的情况,您可以将地图的每个字段分配给新的Data1或的适当字段Data2。


3. 处理这个问题的理想方法是使用json.RawMessage延迟解码Data直到你知道它是什么。这可以这样处理:


type Msg struct {

  MsgType int

  Data interface{}

}


func (m *Msg) UnmarshalJSON(b []byte) (err error) {

    var tmp struct {

        MsgType int

        Data json.RawMessage

    }

    err = json.Unmarshal(b, &tmp)

    if err != nil {

        return

    }

    m.MsgType = tmp.MsgType

    switch (tmp.MsgType) {

    case 1:

        data := Data1{}

        err = json.Unmarshal(tmp.Data, &data)

        if err != nil {

            return

        }

        m.Data = data

    case 2:

        data := Data2{}

        err = json.Unmarshal(tmp.Data, &data)

        if err != nil {

            return

        }

        m.Data = data

    default:

        return errors.New("invalid DataType")

    }

    return

}

然后你可以调用json.Unmarshalorjson.Decode直接在 a 上*Msg,它Data会根据你的需要进行解码。


查看完整回答
反对 回复 2023-06-12
  • 1 回答
  • 0 关注
  • 118 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信