Я ищу решение, которое НЕ включает в себя введение дополнительного «универсального» поля, такого как Value
, Data
и т. Д., Которое было бы заполнителем для варианта поля.
Iиметь спецификацию JSON, которая описывает несколько больших структур, которые содержат в основном простые значения, но иногда это значение является самой структурой, с динамическим типом, зависящим от значения определенного поля.
Например, оба этих документа JSON должны быть разбиты на одну и ту же структуру Go:
{
"some_data": "foo",
"dynamic_field": { "type": "A", "name": "Johnny" },
"other_data": "bar"
}
и
{
"some_data": "foo",
"dynamic_field": { "type": "B", "address": "Somewhere" },
"other_data": "bar"
}
Структура JSON установлена, я не могуизмените его.
Структура Go должна выглядеть следующим образом:
type BigStruct struct {
SomeData string `json:"some_data"`
DynamicField Something `json:"dynamic_field"`
OtherData string `json:"other_data"`
}
Вопрос в том, как на самом деле это сделать и каким должен быть тип Something
.
Я начал с создания интерфейса:
type Something interface {
GetType() string
}
И у меня есть несколько структур и функций:
type BaseDynamicType struct {
Type string `json:"type"`
}
type DynamicTypeA struct {
BaseDynamicType
Name string `json:"name"`
}
type DynamicTypeB struct {
BaseDynamicType
Address string `json:"address"`
}
func (d *BaseDynamicType) GetType() string {
return d.Type
}
Причина в том, что когда я получаю экземплярBigStruct
, я могу сделать это:
switch big.DynamicField.GetType() {
case "A": // do something with big.DynamicField cast to DynamicTypeA
case "B": // do something with big.DynamicField cast to DynamicTypeB
}
Однако потом я застрял - как это соглашение может работать с UnmarshalJSON
?Я думаю, что BigStruct
должен реализовывать UnmarshalJSON
, который каким-то образом проверяет поле Type
dynamic_field
, а затем на его основе делает DynamicField
либо DynamicTypeA
, либо DynamicTypeB
.
* 1040.*Но как?Один из способов, который, вероятно, не работает из-за рекурсии:
- Пометить
DynamicField
как json:"-"
- Реализовать
UnmarshalJSON
для BigStruct - unmarshalJSON в
map[string]interface{}
в BigStruct
в UnmarshalJSON
, - , проверить значение
dynamic_field
на карте, вручную построить либо DynamicTypeA
, либо DynamicTypeB
- снова демаршируйте те же данные в
BigStruct
- , исправьте
DynamicField
с вручную созданными значениями
... но это приведет к бесконечной рекурсии на 5-м шаге, когда япопытайтесь распаковать данные в BigStruct
, который вызовет ту же функцию UnmarshalJSON
, которая выполняется в настоящее время.