Как сериализовать и десериализовать данные в Go?

Ответ

В Go сериализация (преобразование данных в формат для хранения или передачи) и десериализация (обратный процесс) обычно выполняются с помощью стандартных пакетов encoding/json, encoding/xml, encoding/gob или encoding/binary.

JSON (наиболее популярный вариант):

Используется пакет encoding/json.

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Person struct {
    Name string `json:"name"` // Тег для кастомизации имени поля в JSON
    Age  int    `json:"age"`
    // Поля должны быть экспортируемыми (начинаться с заглавной буквы)
}

func main() {
    // Сериализация (Marshal): Go-структура -> JSON-байты
    person1 := Person{"Alice", 30}
    jsonData, err := json.Marshal(person1)
    if err != nil {
        log.Fatalf("Ошибка сериализации: %v", err)
    }
    fmt.Printf("JSON данные: %sn", string(jsonData)) // JSON данные: {"name":"Alice","age":30}

    // Для красивого вывода JSON (с отступами)
    prettyJSONData, err := json.MarshalIndent(person1, "", "  ")
    if err != nil {
        log.Fatalf("Ошибка сериализации с отступами: %v", err)
    }
    fmt.Printf("Красивый JSON:n%sn", string(prettyJSONData))

    // Десериализация (Unmarshal): JSON-байты -> Go-структура
    var person2 Person
    err = json.Unmarshal(jsonData, &person2)
    if err != nil {
        log.Fatalf("Ошибка десериализации: %v", err)
    }
    fmt.Printf("Десериализованная структура: %+vn", person2) // Десериализованная структура: {Name:Alice Age:30}
}

XML и Gob:

Работают аналогично, используя пакеты encoding/xml и encoding/gob соответственно. encoding/gob часто используется для передачи данных между Go-программами.

Protobuf:

Для высокопроизводительной и кросс-языковой сериализации часто используется Protocol Buffers (github.com/golang/protobuf или google.golang.org/protobuf). Требует определения схемы данных.

Бинарная сериализация:

Пакет encoding/binary позволяет читать и записывать данные в бинарном формате, что полезно для низкоуровневых протоколов или работы с файлами.

Важные нюансы:

  • Экспортируемые поля: Для сериализации/десериализации поля структуры должны быть экспортируемыми (начинаться с заглавной буквы).
  • Теги: Теги, такие как json:"name", позволяют управлять именами полей в сериализованном формате, пропускать поля (json:"-") или делать их опциональными (json:"name,omitempty").
  • Обработка ошибок: Всегда проверяйте возвращаемое значение err после операций сериализации/десериализации.
  • Потоковая обработка: Для работы с большими объемами данных используйте json.Encoder и json.Decoder с io.Reader и io.Writer для потоковой обработки без загрузки всего содержимого в память.

Ответ 18+ 🔞

Давай разберём эту тему про сериализацию в Go, а то тут, блядь, как в огороде бузина, а в Киеве дядька. Всё вроде просто, но есть нюансы, ёпта.

JSON — наш главный по тарелочкам

Чаще всего юзают encoding/json. Работает, как швейцарские часы, если не накосячить.

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Person struct {
    Name string `json:"name"` // Смотри, теги! Это чтобы JSON не орал "а где name?"
    Age  int    `json:"age"`
    // Важный момент, ёпта: поля должны быть с большой буквы! Иначе json их в упор не видит.
}

func main() {
    // Сериализация (Marshal): Из нашей структуры делаем JSON-байты
    person1 := Person{"Alice", 30}
    jsonData, err := json.Marshal(person1)
    if err != nil {
        log.Fatalf("Ошибка сериализации: %v", err) // Всегда проверяй ошибку, а то потом волнение ебать
    }
    fmt.Printf("JSON данные: %sn", string(jsonData)) // Выведет: {"name":"Alice","age":30}

    // А если хочется красиво, с отступами, как для важной персоны
    prettyJSONData, err := json.MarshalIndent(person1, "", "  ")
    if err != nil {
        log.Fatalf("Ошибка сериализации с отступами: %v", err)
    }
    fmt.Printf("Красивый JSON:n%sn", string(prettyJSONData))

    // Десериализация (Unmarshal): Из JSON-байтов собираем обратно структуру
    var person2 Person
    err = json.Unmarshal(jsonData, &person2) // Не забудь амперсанд, а то нихуя не запишется!
    if err != nil {
        log.Fatalf("Ошибка десериализации: %v", err)
    }
    fmt.Printf("Десериализованная структура: %+vn", person2) // {Name:Alice Age:30}
}

XML, Gob и прочая шушера

  • XML — через encoding/xml. Тот же принцип, только теги другие. Для любителей старой школы.
  • Gob (encoding/gob) — это наш, гоферский, внутренний формат. Супер-пупер для общения между двумя Go-программами. Быстро и без лишних телодвижений.
  • Protobuf — это уже серьёзная артиллерия. Для максимальной производительности и когда надо общаться с питоном или жабой. Требует отдельной схемы, но оно того стоит, если данные овердохуища.

Бинарная сериализация

encoding/binary — это когда тебе нужно вручную, побитово, как в старые добрые. Для своих протоколов или чтения/записи специфичных файлов. Сильно, но и головной боли можно наебаться.

Важные нюансы, на которых все обжигаются:

  1. Экспортируемые поля, блядь! Поля в структуре должны быть с большой буквы (Name, Age). Иначе json.Marshal посмотрит на них, как баран на новые ворота, и проигнорирует. Тишина в JSON-файле будет.
  2. Теги — твои лучшие друзья. json:"name" — говорит, как поле назвать в JSON. json:"-" — чтобы нахрен его выкинуть. json:"name,omitempty" — чтобы не светить пустое поле. Учи матчасть!
  3. Ошибки, ёпта! err — это святое. Всегда проверяй после Marshal и Unmarshal. Иначе потом будешь искать, почему данные — хуй с горы, а не то, что ожидал.
  4. Для больших данных — потоки. Если данных дохуя, не грузи всё в память. Используй json.NewEncoder(writer) и json.NewDecoder(reader). Они будут кушать данные по кусочкам, как мартышлюшка банан.

Вот и вся магия. Главное — не выёбывайся с бинарными форматами, если можно обойтись JSON. И проверяй ошибки, а то сам от себя охуеешь потом.