本文介绍了将通用 JSON 对象解码为多种格式之一的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 Go 中开发基于 JSON 的通用消息传递协议.我想要做的是有一个 BaseMessage 有一般信息,如 Typetimestamp 等.但同时我想能够为某些类型的数据定义更具体的消息结构.

I am working on a general JSON based message passing protocol in Go. What I would like to do is have a BaseMessage that has general information like Type, timestamp, etc. But at the same time I want to be able to define more specific message structures for certain types of data.

例如:

type Message struct {
    Type      string `json:type`
    Timestamp string `json:timestamp`

}

type EventMessage struct {
    Message
    EventType string
    EventCreator string
    EventData interface{}
}

我有一组处理程序,为了确定哪个处理程序应该处理消息,我首先将 JSON 解码为常规 Message 类型以检查 Type 字段.对于此示例,我将获取与事件"消息类型关联的处理程序.

I have a set of handlers and to determine which handler should process the message I decode the JSON to the general Message type first to check the Type field. For this example I would get the handler associated with an "Event" message type.

当我想在结构上断言 EventMessage 类型时遇到问题.

I run into problems when I then want to assert the EventMessage type onto the structure.

以下代码非常粗略,但希望它能显示我对如何处理消息的总体思路.

The following code is very rough, but hopefully it displays my general idea of how I am trying to handle the messages.

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 解码器只是创建了一个地图,然后我无法断言任何一种类型.我已经找到了使其成为可能的解决方法,但它非常丑陋,可能效率不高,而且很可能容易出错.我想让事情简单明了,以便可以轻松维护此代码.

I have tried to use an interface{} but then the JSON decoder just creates a map which I then cant assert either type on. I have figured out workarounds that make it possible, but its very ugly, probably not efficient, and most likely error prone. I would like to keep things simple and straightforward so this code can be easily maintained.

是否有一种在 Go 中处理通用 JSON 对象的方法,以便解码后的 JSON 可以是多种结构格式中的一种?

我也想过在主 Message 结构的 Data interface{} 中包含更具体的信息,但后来我遇到了同样的问题无法在接口上断言任何类型.必须有更好的方法来处理我缺少的 JSON 格式.

I have also played with the idea of having more specific info in a Data interface{} in the main Message struct, but then I run into the same problem of not being able to assert any types onto the interface. There has to be a better way to handle JSON formats that I am just missing.

推荐答案

处理这个问题的一种方法是使用 json.RawMessage 字段来捕获消息的变体部分.将 json.RawMessage 解码为特定于变体的类型:

One way to handle this is to define a struct for the fixed part of the message with a json.RawMessage field to capture the variant part of the message. Decode the json.RawMessage to a type specific to the variant:

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 对象解码为多种格式之一的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-01 07:53