为什么去 json.Unmarshal auto convert interface{} to map
Why go json.Unmarshal auto convert interface{} to map
程序会收到很多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,它是一个映射,而不是接口{},所以当我通过msg.Data.(Data1)将它转换为Data1时,得到了一个错误。
所以,
1. 为什么interface{}会自动转为map?
2.如何转换成我想要的Data1结构?
3.这个场景的最佳实践是什么
1。因为它看到一个 JSON 对象,并且如文档所述,当存储到 interface{}
中时,一个 JSON 对象变成一个 map[string]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
}
然后你可以直接在 *Msg
上调用 json.Unmarshal
或 json.Decode
并且它的 Data
将根据你的需要进行解码。
程序会收到很多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,它是一个映射,而不是接口{},所以当我通过msg.Data.(Data1)将它转换为Data1时,得到了一个错误。
所以,
1. 为什么interface{}会自动转为map?
2.如何转换成我想要的Data1结构?
3.这个场景的最佳实践是什么
1。因为它看到一个 JSON 对象,并且如文档所述,当存储到 interface{}
中时,一个 JSON 对象变成一个 map[string]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
}
然后你可以直接在 *Msg
上调用 json.Unmarshal
或 json.Decode
并且它的 Data
将根据你的需要进行解码。