将通用 JSON 对象解码为多种格式之一
Decoding generic JSON objects to one of many formats
我正在研究一种通用的基于 JSON 的 Go 消息传递协议。我想做的是有一个 BaseMessage
,其中包含 Type
、timestamp
等一般信息。但与此同时,我希望能够为某些类型的数据。
例如:
type Message struct {
Type string `json:type`
Timestamp string `json:timestamp`
}
type EventMessage struct {
Message
EventType string
EventCreator string
EventData interface{}
}
我有一组处理程序,为了确定哪个处理程序应该处理消息,我首先将 JSON 解码为一般 Message
类型以检查 Type
字段。对于此示例,我将获取与 "Event" 消息类型关联的处理程序。
当我想将 EventMessage
类型断言到结构上时,我 运行 遇到了问题。
下面的代码非常粗糙,但希望它展示了我对如何尝试处理消息的总体想法。
type Handler func(msg Message) Message
handlers := make(map[string]Handler)
var msg Message
decoder.Decode(&msg)
handler := handlers[msg.Type]
handler(msg)
我曾尝试使用 interface{}
,但 JSON 解码器只是创建了一个映射,然后我无法断言任何一种类型。我已经找到了使它成为可能的解决方法,但它非常难看,可能效率不高,而且很可能容易出错。我想让事情简单明了,以便可以轻松维护此代码。
在 Go 中是否有处理通用 JSON 对象的方法,以便解码的 JSON 可以是许多结构格式之一?
我也曾想过在主 Message
结构的 Data interface{}
中包含更多具体信息的想法,但后来我 运行 遇到了同样的问题,无法在接口上断言任何类型。必须有更好的方法来处理我所缺少的 JSON 格式。
处理此问题的一种方法是为消息的固定部分定义一个结构,其中包含 json.RawMessage 字段以捕获消息的可变部分。将 json.RawMessage 解码为特定于变体的类型:
type Message struct {
Type string `json:"type"`
Timestamp string `json:"timestamp"`
Data json.RawMessage
}
type Event struct {
Type string `json:"type"`
Creator string `json:"creator"`
}
var m Message
if err := json.Unmarshal(data, &m); err != nil {
log.Fatal(err)
}
switch m.Type {
case "event":
var e Event
if err := json.Unmarshal([]byte(m.Data), &e); err != nil {
log.Fatal(err)
}
fmt.Println(m.Type, e.Type, e.Creator)
default:
log.Fatal("bad message type")
}
我正在研究一种通用的基于 JSON 的 Go 消息传递协议。我想做的是有一个 BaseMessage
,其中包含 Type
、timestamp
等一般信息。但与此同时,我希望能够为某些类型的数据。
例如:
type Message struct {
Type string `json:type`
Timestamp string `json:timestamp`
}
type EventMessage struct {
Message
EventType string
EventCreator string
EventData interface{}
}
我有一组处理程序,为了确定哪个处理程序应该处理消息,我首先将 JSON 解码为一般 Message
类型以检查 Type
字段。对于此示例,我将获取与 "Event" 消息类型关联的处理程序。
当我想将 EventMessage
类型断言到结构上时,我 运行 遇到了问题。
下面的代码非常粗糙,但希望它展示了我对如何尝试处理消息的总体想法。
type Handler func(msg Message) Message
handlers := make(map[string]Handler)
var msg Message
decoder.Decode(&msg)
handler := handlers[msg.Type]
handler(msg)
我曾尝试使用 interface{}
,但 JSON 解码器只是创建了一个映射,然后我无法断言任何一种类型。我已经找到了使它成为可能的解决方法,但它非常难看,可能效率不高,而且很可能容易出错。我想让事情简单明了,以便可以轻松维护此代码。
在 Go 中是否有处理通用 JSON 对象的方法,以便解码的 JSON 可以是许多结构格式之一?
我也曾想过在主 Message
结构的 Data interface{}
中包含更多具体信息的想法,但后来我 运行 遇到了同样的问题,无法在接口上断言任何类型。必须有更好的方法来处理我所缺少的 JSON 格式。
处理此问题的一种方法是为消息的固定部分定义一个结构,其中包含 json.RawMessage 字段以捕获消息的可变部分。将 json.RawMessage 解码为特定于变体的类型:
type Message struct {
Type string `json:"type"`
Timestamp string `json:"timestamp"`
Data json.RawMessage
}
type Event struct {
Type string `json:"type"`
Creator string `json:"creator"`
}
var m Message
if err := json.Unmarshal(data, &m); err != nil {
log.Fatal(err)
}
switch m.Type {
case "event":
var e Event
if err := json.Unmarshal([]byte(m.Data), &e); err != nil {
log.Fatal(err)
}
fmt.Println(m.Type, e.Type, e.Creator)
default:
log.Fatal("bad message type")
}