为什么要去json.Unmarshal自动转换接口{}来映射

问题描述 投票:-2回答:1

该程序将收到许多msg,msg有不同的struct“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,它是一个地图,而不是接口{},所以当我通过msg.Data。(Data1)将它转换为Data1时,得到了一个错误。 所以, 1.为什么界面{}自动转换为地图? 2.如何将其转换为我想要的Data1结构? 3.这个场景中的最佳实践是什么?

go unmarshalling
1个回答
1
投票

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

2.鉴于您目前的情况,您可以将地图的每个字段分配给新的Data1Data2的相应字段。

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.Unmarshal上调用json.Decode*Msg,它的Data将根据你的需要进行解码。

© www.soinside.com 2019 - 2024. All rights reserved.