📊 Эффективная работа с JSON в Go
В статье рассматриваются основные подходы для работы с JSON в языке Go. Большое внимание уделено определениям из документации, а также конкретным примерам.
Введение в JSON
JSON (JavaScript Object Notation) – это легкий формат обмена данными, основанный на синтаксисе объектов JavaScript. Он широко используется для передачи информации между клиентом и сервером в сетевых приложениях.
JSON представляет данные в виде пар «ключ-значение» и может содержать массивы, числа, строки, логические значения и null. Он обеспечивает простоту чтения и записи для людей, а также легкость разбора и генерации для компьютеров.
Чтение JSON
Десериализация (чтение JSON) – это процесс преобразования данных из формата JSON в объекты Go. Для этих целей используется пакет encoding/json
, который входит в стандартную библиотеку языка. Основная функция для чтения Unmarshal
считывает JSON-данные и сохраняет результат в значении, на которое указывает заданная переменная. Если же она представляет собой nil или не является указателем, то функция вернет InvalidUnmarshalError
.
Общая сигнатура: func Unmarshal(data []byte, v any) error
Рассмотрим применение функции Unmarshal
на конкретном примере:
В результате работы программы будет выведено "{Петя 18 программист}".
- Функция
Unmarshal
обладает интересной особенностью – она считывает только поля, соответствующие объявленным типам. Такое поведение используется для выборки определенных данных из большого JSON-файла.
В следующем примере будут заполнены только поля Name
и Age
, а Job
останется проигнорированным. Вывод будет следующий: "{Витя 20 }".
Запись JSON
Сериализация (запись JSON) – это процесс преобразования объекта в формат, который можно сохранить или передать по сети. Для этого в Go используется функция Marshal()
из ранее рассмотренного пакета encoding/json
. Она возвращает два значения – срез байт и ошибку.
Её сигнатура имеет следующий вид: func Marshal(v any) ([]byte, error)
Стоит учитывать, что записаны могут быть только структуры данных, представимые в виде корректного формата JSON.
- Для кодировки типа map он должен иметь вид
map[string]T
, где T – любой тип, поддерживаемый пакетомencoding/json
. - Циклические структуры данных могут привести к попаданию функции
Marshal
в бесконечный цикл, поэтому не поддерживаются для преобразования. - Для кодирования указателей необходимо представить их в виде значений, на которые они указывают. В случае nil-указателей это будет nil.
- Функции, каналы и тип complex не поддерживаются.
Потоковые кодировщики и декодеры
Интерфейсы Reader и Writer
В Go существуют два основных интерфейса из пакета io
стандартной библиотеки, io.Reader
и io.Writer
. Они широко используются для ввода/вывода данных, при работе с файлами, сетевыми соединениями и другими объектами, поддерживающими операции чтения и записи.
Интерфейс io.Reader
определяет метод Read
, который принимает в качестве параметра буфер для чтения, а возвращает количество байт, прочитанных из источника, и ошибку. При завершении потока данных io.Reader
возвращает ошибку io.EOF
(конец файла).
Интерфейс io.Writer
определяет метод Write
, который принимает в качестве параметра буфер для записи данных, а возвращает количество байт, записанных в целевой объект, и ошибку.
При желании каждый разработчик может написать собственные интерфейсы Reader
и Writer
, руководствуясь соглашениями языка.
Кодировщик json.Encoder
Структура json.Encoder
предназначена для кодирования JSON-данных и их последующей записи в выходной поток Writer
.
Так выглядит сигнатура функции для создания кодировщика: func NewEncoder(w io.Writer) *Encoder
Декодер json.Decoder
Структура json.Decoder
позволяет декодировать данные JSON из интерфейса Reader
. К примеру, из файла, буфера или сетевого соединения. Decoder
также обеспечивает возможность контроля синтаксических ошибок и обработки потока JSON-данных в режиме реального времени.
Сигнатура для создания декодера: func NewDecoder(r io.Reader) *Decoder
Рассмотрим пример использования этой функции.
На экран будет выведено: Иван 10
Тип NullString
В Go есть специальный тип NullString
для работы с пустыми или отсутствующими значениями JSON-данных. Он позволяет явно указать, является ли строка пустой или нулевой.
Стандартная библиотека Go не предоставляет встроенного типа NullString
, но можно создать его самостоятельно, используя структуру или указатель на строку.
Тип NullString
также бывает полезен для десериализации JSON-данных в нестандартном формате. С его помощью можно создавать собственные функции наподобие Unmarshal
.
В качестве примера создадим кастомный десериализатор с использованием NullString
.
Декодирование неизвестных данных
Зачастую в JSON хранятся данные разных типов, которые необходимо правильно обработать. В этом случае может помочь декодирование значений в интерфейс и их последующий перебор с использованием switch-case. Такой подход позволяет сохранить преимущества безопасности типов.
Для детального понимания рассмотрим конкретный пример.
Вывод будет следующий: