Лучший способ представить этот JSON в Go?

Я пишу конечную точку, чтобы вернуть данные для Geckoboard, за исключением такого формата:

{
  "item": [
    {
      "value": "274057"
    },
    [
      "38594",
      "39957",
      "35316",
      "35913",
      "36668",
      "45660",
      "41949"
    ]
  ]
}

"item" это массив различных структур. Как бы я представлял эти данные в Go?

Примечание: это не о том, как я могу разобрать это, мне нужно создать этот формат.

2 ответа

Решение

Это проще, чем вы думаете. Это просто не так хорошо задокументировано для обычного читателя. Я бы посоветовал ffjson сверх нормы json Тхо. Он составлен таким образом, что вам не нужно менять синтаксис, кроме имени библиотеки.

Это так просто:

type User struct {
    Id      int    `json:'id'`
    Name    string `json:name`
    SomeId1 int    `json:some_id_1`
    SomeId2 int    `json:some_id_2`
    SomeId3 int    `json:some_id_3`
    SomeId4 int    `json:some_id_4`
}

item := map[string]User{}
for i := 0; i < 10; i++ {
    item[strconv.itoa(i)] = User{i, "Username X", 38393, 29384, 12393, 123981}
}
buf, err := ffjson.Marshal(&item)

Обратная сторона структур (даже в ffjson все еще) это что reflection всегда будет использоваться, что в моменты, когда вам нужна высокая производительность, вы будете тратить много циклов ЦП. ffjson в 2-3 раза быстрее, чем обычно json когда вы держите это на картах. Таким образом, библиотека может компилировать каждую структуру данных, которую вы маршалируете, и повторно использовать ее вместо того, чтобы постоянно проверять целостность / структуру данных с помощью reflect,

Существует простой способ создать значение некоторой структуры данных, в которой вы знаете вывод JSON, который вы хотите сгенерировать / продублировать:

Возьмите вывод, который вы хотите сгенерировать, и распакуйте его в map[string]interface{}, Вы получите значение карты, которое, когда вы выполните маршал, даст желаемый результат. Когда вы отменяете ожидаемый результат, вы можете проверить значение карты результата, чтобы узнать, что вам нужно создать для ожидаемого результата.

Это работает и в вашем случае. Вот код:

var m map[string]interface{}
err := json.Unmarshal([]byte(input), &m)
if err != nil {
    panic(err)
}
fmt.Printf("%+v\n", m)

res, err := json.MarshalIndent(m, "", "  ")
if err != nil {
    panic(err)
}
fmt.Println(string(res))

куда input Ваш вход JSON:

const input = `{
  "item": [
    {
      "value": "274057"
    },
    [
      "38594",
      "39957",
      "35316",
      "35913",
      "36668",
      "45660",
      "41949"
    ]
  ]
}`

Эта программа генерирует тот же вывод, что и требуемый вывод (или ввод):

map[item:[map[value:274057] [38594 39957 35316 35913 36668 45660 41949]]]
{
  "item": [
    {
      "value": "274057"
    },
    [
      "38594",
      "39957",
      "35316",
      "35913",
      "36668",
      "45660",
      "41949"
    ]
  ]
}

Попробуйте полное приложение на игровой площадке Go.

Анализируя ценность вашей карты без разбора:

Очевидно, у него есть ключ "item", тип его значения:

fmt.Printf("%T\n", m["item"]); // Prints []interface{}

Так что это кусочек. Имеет 2 значения, их типы:

fmt.Printf("%T\n", m["item"].([]interface{})[0]); // map[string]interface{}
fmt.Printf("%T\n", m["item"].([]interface{})[1]); // []interface{}

Итак, срез содержит 2 значения:

  • карта ("value" : "274057" пара)
  • и еще один фрагмент (список идентификаторов или номеров)

Вот код Go для воспроизведения того же значения карты:

m := map[string]interface{}{
    "item": []interface{}{
        map[string]interface{}{"value": "274057"},
        []interface{}{"38594", "39957", "35316", "35913", "36668", "45660", "41949"},
    },
}

Маршалинг это дает тот же вывод JSON.

Другие вопросы по тегам