#json #go
#json #Вперед #отмена сопоставления
Вопрос:
Я работаю над общим протоколом передачи сообщений на основе 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
поле. Для этого примера я бы получил обработчик, связанный с типом сообщения «Событие».
Я сталкиваюсь с проблемами, когда затем хочу утвердить EventMessage
тип в структуре.
Следующий код очень приблизительный, но, надеюсь, он отображает мое общее представление о том, как я пытаюсь обрабатывать сообщения.
type Handler func(msg Message) Message
handlers := make(map[string]Handler)
var msg Message
decoder.Decode(amp;msg)
handler := handlers[msg.Type]
handler(msg)
Я пытался использовать interface{}
, но затем декодер JSON просто создает карту, на которой я затем не могу утверждать ни один тип. Я нашел обходные пути, которые делают это возможным, но это очень некрасиво, вероятно, неэффективно и, скорее всего, подвержено ошибкам. Я хотел бы, чтобы все было просто и понятно, чтобы этот код можно было легко поддерживать.
Существует ли метод обработки общих объектов JSON в Go, чтобы декодированный JSON мог быть одним из многих форматов struct?
Я также играл с идеей иметь более конкретную информацию в a Data interface{}
в основной Message
структуре, но затем я столкнулся с той же проблемой невозможности утверждать какие-либо типы в интерфейсе. Должен быть лучший способ обработки форматов JSON, который мне просто не хватает.
Ответ №1:
Один из способов справиться с этим — определить структуру для фиксированной части сообщения с помощью 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, amp;m); err != nil {
log.Fatal(err)
}
switch m.Type {
case "event":
var e Event
if err := json.Unmarshal([]byte(m.Data), amp;e); err != nil {
log.Fatal(err)
}
fmt.Println(m.Type, e.Type, e.Creator)
default:
log.Fatal("bad message type")
}
Комментарии:
1. Спасибо, это работает замечательно. Я не думал использовать RawMessage!