Какие типы данных в Go используются для работы с JSON?

Ответ

В Go для работы с JSON, как правило, используют два основных подхода:

  1. Структуры (struct) с тегами полей (рекомендуемый способ)

    Это идиоматичный и наиболее предпочтительный способ для работы с JSON, структура которого заранее известна. Он обеспечивает типобезопасность и прозрачность кода.

    import "encoding/json"
    
    type Person struct {
        Name   string   `json:"name"`
        Age    int      `json:"age,omitempty"` // omitempty - не включать в JSON, если значение нулевое
        Skills []string `json:"skills"`
    }

    Для кодирования (Go -> JSON) и декодирования (JSON -> Go) используются функции json.Marshal и json.Unmarshal из стандартной библиотеки encoding/json.

  2. Карта map[string]interface{}

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

    var data map[string]interface{}
    jsonData := []byte(`{"name":"Alice","age":25}`)
    json.Unmarshal(jsonData, &data)
    // data["name"] будет равно "Alice"

    Недостаток: Теряется типобезопасность. Для доступа к значениям требуются приведения типов (data["age"].(float64)), что может привести к панике во время выполнения, если тип окажется другим.

Ответ 18+ 🔞

А, слушай, про JSON в Go? Ну, тут всё просто, как три копейки, но есть нюансы, блядь. В основном два пути, и один из них — это как идти в магазин за хлебом, а другой — как пытаться объяснить бабушке, что такое интернет.

Первый способ — по-взрослому, с структурами. Это когда ты заранее знаешь, какая тебе херня прилетит. Типобезопасно, красиво, все довольны. Заводишь себе структуру, как костюмчик по фигуре, и навешиваешь на поля теги эти, json:"как_там_в_джейсоне".

import "encoding/json"

type Person struct {
    Name   string   `json:"name"`
    Age    int      `json:"age,omitempty"` // omitempty — гениальная штука, чтоб не светить нули, если их нет
    Skills []string `json:"skills"`
}

Дальше просто: json.Marshal — чтобы свою структуру в JSON превратить, json.Unmarshal — чтобы входящий JSON обратно в структуру запихнуть. Всё чётко, всё предсказуемо. Рекомендуемый способ, ёпта. Как по рельсам.

А второй способ — это уже для отчаянных, когда структура JSON неизвестна или меняется, как погода в Питере. Берёшь map[string]interface{} — это такая универсальная свалка, куда можно запихнуть что угодно.

var data map[string]interface{}
jsonData := []byte(`{"name":"Alice","age":25}`)
json.Unmarshal(jsonData, &data)
// Ну и потом data["name"] будет "Alice", да.

Но вот тут, блядь, подвох: типобезопасность накрывается медным тазом. Чтобы достать age, тебе надо делать приведение типа: data["age"].(float64). И если ты ошибёшься с типом — получишь панику во время выполнения, прям как обоссаться со смеху, когда не надо. Овердохуища риска, если не уверен.

Так что, если можешь — всегда используй структуры. Это надёжнее. А map[string]interface{} — это уже для крайних случаев, когда JSON приходит такой, что сам его создатель, пизда, уже не помнит, что там внутри.