Введение в работу с JSON в Go
JSON (JavaScript Object Notation) — это лёгкий формат обмена данными, который широко используется в веб-разработке, API и конфигурационных файлах. Язык Go (Golang) предоставляет встроенный пакет encoding/json, который позволяет легко выполнять парсинг (декодирование) и сериализацию (кодирование) данных. В этой статье мы разберём основы работы с JSON в Go на практических примерах, понятных даже начинающим разработчикам.
Основы пакета encoding/json
Пакет encoding/json — это стандартная библиотека Go, которая не требует дополнительной установки. Два главных инструмента в этом пакете — функции json.Marshal (сериализация) и json.Unmarshal (десериализация).
Структуры и теги JSON
В Go данные обычно представляются в виде структур (struct). Для управления именами полей в JSON используются теги. Рассмотрим простой пример:
package main
import (
"encoding/json"
"fmt"
)
// Определяем структуру с тегами JSON
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email,omitempty"`
IsAdmin bool `json:"is_admin"`
}
func main() {
// Создаём экземпляр структуры
person := Person{
Name: "Иван Петров",
Age: 30,
Email: "ivan@example.com",
IsAdmin: true,
}
// Сериализуем в JSON
jsonData, _ := json.Marshal(person)
fmt.Println(string(jsonData))
}
Результат выполнения:
{"name":"Иван Петров","age":30,"email":"ivan@example.com","is_admin":true}
Важные моменты:
- Тег
json:"name"указывает, как поле будет называться в JSON - Опция
omitemptyпропускает пустые поля (нулевые значения) - Поля структуры должны быть экспортируемыми (начинаться с большой буквы)
Сериализация (Marshal) данных в JSON
Сериализация — это процесс преобразования Go-структуры или другого типа данных в строку JSON. Функция json.Marshal возвращает срез байтов ([]byte) и ошибку.
Примеры сериализации разных типов
package main
import (
"encoding/json"
"fmt"
)
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
Price float64 `json:"price"`
Tags []string `json:"tags,omitempty"`
InStock bool `json:"in_stock"`
}
func main() {
// Сериализация структуры
product := Product{
ID: 101,
Name: "Ноутбук",
Price: 79999.99,
Tags: []string{"электроника", "ноутбуки"},
InStock: true,
}
// Красивый вывод с отступами
jsonData, _ := json.MarshalIndent(product, "", " ")
fmt.Println(string(jsonData))
// Сериализация среза структур
products := []Product{
{ID: 1, Name: "Мышь", Price: 1500.00, InStock: true},
{ID: 2, Name: "Клавиатура", Price: 3500.00, InStock: false},
}
jsonArray, _ := json.Marshal(products)
fmt.Println(string(jsonArray))
}
Результат:
{
"id": 101,
"name": "Ноутбук",
"price": 79999.99,
"tags": [
"электроника",
"ноутбуки"
],
"in_stock": true
}
[{"id":1,"name":"Мышь","price":1500,"in_stock":true},{"id":2,"name":"Клавиатура","price":3500,"in_stock":false}]
Парсинг (Unmarshal) JSON в Go
Парсинг — это обратный процесс: преобразование строки JSON в структуру Go. Для этого используется функция json.Unmarshal.
Базовый пример парсинга
package main
import (
"encoding/json"
"fmt"
"log"
)
type User struct {
Username string `json:"username"`
Age int `json:"age"`
City string `json:"city"`
}
func main() {
// JSON-строка для парсинга
jsonString := `{"username":"alex","age":25,"city":"Москва"}`
// Создаём переменную для результата
var user User
// Парсим JSON
err := json.Unmarshal([]byte(jsonString), &user)
if err != nil {
log.Fatal("Ошибка парсинга JSON:", err)
}
fmt.Printf("Имя: %s, Возраст: %d, Город: %s\n",
user.Username, user.Age, user.City)
}
Парсинг вложенных структур
package main
import (
"encoding/json"
"fmt"
"log"
)
type Address struct {
Street string `json:"street"`
City string `json:"city"`
ZipCode string `json:"zip_code"`
}
type Employee struct {
Name string `json:"name"`
Age int `json:"age"`
Address Address `json:"address"`
Skills []string `json:"skills"`
}
func main() {
complexJSON := `{
"name": "Мария Соколова",
"age": 28,
"address": {
"street": "ул. Ленина, 15",
"city": "Санкт-Петербург",
"zip_code": "190000"
},
"skills": ["Go", "Python", "JavaScript"]
}`
var employee Employee
err := json.Unmarshal([]byte(complexJSON), &employee)
if err != nil {
log.Fatal("Ошибка:", err)
}
fmt.Printf("Сотрудник: %s\n", employee.Name)
fmt.Printf("Адрес: %s, %s\n", employee.Address.City, employee.Address.Street)
fmt.Printf("Навыки: %v\n", employee.Skills)
}
Обработка ошибок и неопределённых данных
При работе с JSON важно правильно обрабатывать ошибки. Часто встречаются случаи, когда JSON содержит неизвестные поля или данные отсутствуют.
Использование map[string]interface{}
package main
import (
"encoding/json"
"fmt"
"log"
)
func main() {
// Неизвестная структура JSON
jsonData := `{
"name": "Тестовый объект",
"value": 42,
"active": true,
"metadata": {
"version": 2,
"author": "admin"