JSON обработка в Go (Golang): от основ до продвинутых техник
Go (Golang) предлагает мощный и интуитивно понятный набор инструментов для работы с JSON. Стандартная библиотека encoding/json покрывает 95% задач, а для высоконагруженных проектов существуют более производительные альтернативы. В этой статье мы разберём все аспекты JSON-обработки в Go: от базовой сериализации до кастомных парсеров и оптимизации.
1. Основы: стандартная библиотека encoding/json
В Go JSON обрабатывается через пакет encoding/json. Основные операции — маршалинг (сериализация в JSON) и анмаршалинг (десериализация из JSON).
1.1. Маршалинг (struct → JSON)
Для преобразования структуры Go в JSON используется функция json.Marshal():
package main
import (
"encoding/json"
"fmt"
"log"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email,omitempty"` // omitempty - пропустить, если пустое
}
func main() {
user := User{
Name: "Иван Петров",
Age: 30,
Email: "ivan@example.com",
}
jsonData, err := json.Marshal(user)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(jsonData))
// {"name":"Иван Петров","age":30,"email":"ivan@example.com"}
}
Важно: Поля структуры должны быть экспортируемыми (с большой буквы). Теги json:"fieldname" управляют именованием полей в JSON.
1.2. Анмаршалинг (JSON → struct)
Для обратного преобразования используется json.Unmarshal():
func main() {
jsonString := `{"name":"Анна","age":25,"email":"anna@mail.com"}`
var user User
err := json.Unmarshal([]byte(jsonString), &user)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Имя: %s, Возраст: %d\n", user.Name, user.Age)
// Имя: Анна, Возраст: 25
}
2. Работа с вложенными структурами и массивами
JSON часто содержит вложенные объекты и массивы. В Go это отображается на вложенные структуры и срезы:
type Address struct {
City string `json:"city"`
Street string `json:"street"`
ZipCode string `json:"zip_code"`
}
type Company struct {
Name string `json:"name"`
Employees []User `json:"employees"`
Address Address `json:"address"`
}
func main() {
companyJSON := `{
"name": "TechCorp",
"employees": [
{"name":"Олег","age":28,"email":"oleg@tech.com"},
{"name":"Мария","age":32,"email":"maria@tech.com"}
],
"address": {
"city": "Москва",
"street": "Тверская, 10",
"zip_code": "101000"
}
}`
var company Company
json.Unmarshal([]byte(companyJSON), &company)
fmt.Printf("Компания: %s, Город: %s, Сотрудников: %d\n",
company.Name, company.Address.City, len(company.Employees))
}
3. Продвинутые техники
3.1. Кастомная сериализация (интерфейсы Marshaler/Unmarshaler)
Иногда нужно контролировать, как тип преобразуется в JSON. Для этого реализуют интерфейсы json.Marshaler и json.Unmarshaler:
type CustomTime struct {
time.Time
}
const layout = "2006-01-02T15:04:05Z"
func (ct CustomTime) MarshalJSON() ([]byte, error) {
return json.Marshal(ct.Format(layout))
}
func (ct *CustomTime) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
t, err := time.Parse(layout, s)
if err != nil {
return err
}
ct.Time = t
return nil
}
type Event struct {
Title string `json:"title"`
Date CustomTime `json:"date"`
}
3.2. Работа с неструктурированным JSON (map[string]interface{})
Если структура JSON неизвестна заранее, используйте map[string]interface{}:
func main() {
rawJSON := `{"name":"Тест","values":[1,2,3],"active":true}`
var data map[string]interface{}
json.Unmarshal([]byte(rawJSON), &data)
// Доступ к значениям с приведением типов
name := data["name"].(string)
values := data["values"].([]interface{})
fmt.Printf("Имя