我正在Go中研究基于通用JSON的消息传递协议。我想做的是拥有一个BaseMessage具有一般信息,例如Type,timestamp等。但是同时,我希望能够为某些类型的数据定义更具体的消息结构。
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字段。对于此示例,我将获得与“事件”消息类型关联的处理程序。
Message
当我想EventMessage在结构上声明类型时遇到问题。
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解码器仅创建了一个地图,然后我无法断言任何一种类型。我已经找到了使之成为可能的解决方法,但是它非常丑陋,可能效率不高,而且很容易出错。我想使事情简单明了,以便可以轻松维护此代码。
interface{}
Go中是否有处理通用JSON对象的方法,以便解码后的JSON可以是许多结构格式之一?
我也曾想过在Data interface{}主Message结构中的a 中包含更多特定信息,但是随后遇到了一个同样的问题,即无法在接口上声明任何类型。必须有一种更好的方法来处理我刚丢失的JSON格式。
Data interface{}
处理此问题的一种方法是使用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") }
游乐场的例子