📊 Эффективная работа с JSON в Go
В статье рассматриваются основные подходы для работы с JSON в языке Go. Большое внимание уделено определениям из документации, а также конкретным примерам. JSON (JavaScript Object Notation) – это легкий формат обмена данными, основанный на синтаксисе объектов JavaScript. Он широко используется для передачи информации между клиентом и сервером в сетевых приложениях. JSON представляет данные в виде пар «ключ-значение» и может содержать массивы, числа, строки, логические значения и null. Он обеспечивает простоту чтения и записи для людей, а также легкость разбора и генерации для компьютеров. Десериализация (чтение JSON) – это процесс преобразования данных из формата JSON в объекты Go. Для этих целей используется пакет Общая сигнатура: Рассмотрим применение функции В результате работы программы будет выведено «{Петя 18 программист}». В следующем примере будут заполнены только поля 👨💻 Библиотека Go разработчика Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека Go разработчика» 🧩 Библиотека задач по Go Интересные задачи по Go для практики можно найти на нашем телеграм-канале «Библиотека задач по Go» 🎓 Библиотека Go для собеса Подтянуть свои знания по Go вы можете на нашем телеграм-канале «Библиотека Go для собеса» Сериализация (запись JSON) – это процесс преобразования объекта в формат, который можно сохранить или передать по сети. Для этого в Go используется функция Её сигнатура имеет следующий вид: Стоит учитывать, что записаны могут быть только структуры данных, представимые в виде корректного формата JSON. В Go существуют два основных интерфейса из пакета Интерфейс Интерфейс При желании каждый разработчик может написать собственные интерфейсы Структура Так выглядит сигнатура функции для создания кодировщика: Структура Сигнатура для создания декодера: Рассмотрим пример использования этой функции. На экран будет выведено: Иван 10 В Go есть специальный тип Стандартная библиотека Go не предоставляет встроенного типа Тип В качестве примера создадим кастомный десериализатор с использованием Зачастую в JSON хранятся данные разных типов, которые необходимо правильно обработать. В этом случае может помочь декодирование значений в интерфейс и их последующий перебор с использованием switch-case. Такой подход позволяет сохранить преимущества безопасности типов. Для детального понимания рассмотрим конкретный пример. Вывод будет следующий:Введение в JSON
Чтение JSON
encoding/json
, который входит в стандартную библиотеку языка. Основная функция для чтения Unmarshal
считывает JSON-данные и сохраняет результат в значении, на которое указывает заданная переменная. Если же она представляет собой nil или не является указателем, то функция вернет InvalidUnmarshalError
.func Unmarshal(data []byte, v any) error
Unmarshal
на конкретном примере:
type Worker struct { Name string `json:"name"` Age int `json:"age"` Job string `json:"job"` } func main() { var worker Worker jsonData := `{"name":"Петя", "age":18, "job":"Backend-разработчик"}` err := json.Unmarshal([]byte(jsonData), &worker) if err != nil { fmt.Println("Ошибка чтения JSON-данных:", err) } fmt.Println(worker) }
Unmarshal
обладает интересной особенностью – она считывает только поля, соответствующие объявленным типам. Такое поведение используется для выборки определенных данных из большого JSON-файла.Name
и Age
, а Job
останется проигнорированным. Вывод будет следующий: «{Витя 20 }».
type Worker struct { Name string `json:"name"` Age int `json:"age"` Job string `json:"job"` } ... var worker Worker jsonData := `{"name":"Витя", "age": 20, "city":"Москва"}` err := json.Unmarshal([]byte(jsonData), &worker)
Запись JSON
Marshal()
из ранее рассмотренного пакета encoding/json
. Она возвращает два значения – срез байт и ошибку.func Marshal(v any) ([]byte, error)
type Worker struct { Name string `json:"name"` Age int `json:"age"` Job string `json:"job"` } func main() { workerInfo := Worker{Name: "Ваня", Age: 14, Job: "Go-разработчик"} jsonInfo, err := json.Marshal(workerInfo) if err != nil { fmt.Println("Ошибка записи данных:", err) } fmt.Println(jsonInfo) }
map[string]T
, где T – любой тип, поддерживаемый пакетом encoding/json
.Marshal
в бесконечный цикл, поэтому не поддерживаются для преобразования.Потоковые кодировщики и декодеры
Интерфейсы Reader и Writer
io
стандартной библиотеки, io.Reader
и io.Writer
. Они широко используются для ввода/вывода данных, при работе с файлами, сетевыми соединениями и другими объектами, поддерживающими операции чтения и записи.io.Reader
определяет метод Read
, который принимает в качестве параметра буфер для чтения, а возвращает количество байт, прочитанных из источника, и ошибку. При завершении потока данных io.Reader
возвращает ошибку io.EOF
(конец файла).
type Reader interface { Read(p []byte) (n int, err error) }
io.Writer
определяет метод Write
, который принимает в качестве параметра буфер для записи данных, а возвращает количество байт, записанных в целевой объект, и ошибку.
type Writer interface { Write(p []byte) (n int, err error) }
Reader
и Writer
, руководствуясь соглашениями языка.Кодировщик json.Encoder
json.Encoder
предназначена для кодирования JSON-данных и их последующей записи в выходной поток Writer
.func NewEncoder(w io.Writer) *Encoder
type Shape struct { Type string `json:"name"` Width int `json:"width"` Height int `json:"height"` } func main() { // Создание слайса структур Workers с необходимыми данными shapes := []Shape{ {Type: "Квадрат", Width: 10, Height: 10}, {Type: "Прямоугольник", Width: 50, Height: 20}, } var buf bytes.Buffer encoder := json.NewEncoder(&buf) // Запись JSON-данных в буфер if err := encoder.Encode(shapes); err != nil { fmt.Println("Ошибка при записи JSON-данных:", err) return } fmt.Println(buf.String()) }
Декодер json.Decoder
json.Decoder
позволяет декодировать данные JSON из интерфейса Reader
. К примеру, из файла, буфера или сетевого соединения. Decoder
также обеспечивает возможность контроля синтаксических ошибок и обработки потока JSON-данных в режиме реального времени.func NewDecoder(r io.Reader) *Decoder
type Student struct { Name string `json:"name"` Grade int `json:"grade"` } func main() { jsonData := `{"name":"Иван", "grade":10}` // Создание буфера с данными в формате JSON reader := strings.NewReader(jsonData) // Создание Decoder для чтения из буфера decoder := json.NewDecoder(reader) var student Student // Чтение JSON из буфера и их запись в student if err := decoder.Decode(&student); err != nil { fmt.Println("Ошибка декодирования:", err) return } fmt.Println(student.Name, student.Grade) }
Тип NullString
NullString
для работы с пустыми или отсутствующими значениями JSON-данных. Он позволяет явно указать, является ли строка пустой или нулевой.NullString
, но можно создать его самостоятельно, используя структуру или указатель на строку.
type NullString struct { String string Valid bool }
NullString
также бывает полезен для десериализации JSON-данных в нестандартном формате. С его помощью можно создавать собственные функции наподобие Unmarshal
.NullString
.
type NullString struct { String string Valid bool } func (nstr *NullString) UnmarshalCustomData(jsonData []byte) error { // Проверяем, являются ли JSON-данные нулевой строкой if string(jsonData) == "null" { nstr.Valid = false return nil } var s string // Десериализация JSON if err := json.Unmarshal(jsonData, &s); err != nil { return err } // Присвоение строки типу NullString nstr.String = s nstr.Valid = true return nil }
Декодирование неизвестных данных
func main() { jsonData := []byte(`{"name":"Ваня","grade":11,"classmates":["Петя", "Игорь","Глеб"]}`) // Десериализация JSON-данных var data interface{} if err := json.Unmarshal(jsonData, &data); err != nil { fmt.Println("Ошибка при чтении JSON:", err) } // Type assertion res := data.(map[string]interface{}) // Перебор ключей и значений for key, val := range res { switch value := val.(type) { case string: fmt.Println(key, "имеет тип string - ", value) case float64: fmt.Println(key, "имеет тип float64 - ", value) case []interface{}: fmt.Println(key, "имеет тип []interface{} - ", value) default: fmt.Println("Значение элемента неизвестно") } } }
name имеет тип string - Ваня grade имеет тип float64 - 11 classmates имеет тип []interface{} - [Петя Игорь Глеб]
Материалы по теме
- 0 views
- 0 Comment