С учетом следующего JSON
{
"some": "value"
"nested": {
"some": "diffvalue",
"nested": {
"some": "innervalue"
}
}
}
, что примерно соответствует этой структуре:
type Envelope struct {
some string `json:"some"`
nested InnerEnvelope `json:"nested"`
}
, где InnerEnvelope
: type InnerEnvelope map[string]interface{}
Выполнение простогоjson.Unmarshal([]byte value, &target)
здесь не помогает, из-за рекурсивной природы типов исходного JSON.
Я не знаю заранее, насколько глубоко и под какими ключами будут существовать внутренние карты, поэтому я не могу объявить типы заранее..
Идея состоит в том, что использование map[string]interface{}
в качестве типа недостаточно хорошо, так как мне нужно, чтобы значения в InnerEnvelope
были как-то преобразованы и типизированы.Детали не важны, но изображение, мне нужно привести каждое значение внутри NestedEnvelope
типа bool в виде строки, говорящей «true» или «false», в отличие от фактического bool
типа.
Я обратился к UnmarshalJSON
интерфейсу, чтобы решить эту проблему.Я легко могу сделать это на верхнем уровне следующим образом:
func (m *Envelope) UnmarshalJSON(b []byte) error {
var stuff noBoolMap
if err := json.Unmarshal(b, &stuff); err != nil {
return err
}
for key, value := range stuff {
switch value.(type) {
case bool:
stuff[key] = strconv.FormatBool(value.(bool))
}
}
return nil
}
Но так как внутренние json.Unmarshal
уже будут иметь внутренние карты, проанализированные как map[string]interface{}
, мне нужно было бы еще раз пройти через внутреннийкарты, приведите их к соответствующему типу и выполните мои преобразования значений.
Итак, мой вопрос: в таком случае, как это будет подходить в Go, и предпочтительно делать это за один проход?
Ожидаемый результат примера JSON выше:
Envelope {
some: string
nested: InnerEnvelope {
some: string {
nested: InnerEnvelope {
some: string
}
}
}