JSON обработка в Go (Golang): полное руководство
Go (Golang) — это современный компилируемый язык программирования, разработанный в Google. Одной из его сильных сторон является встроенная поддержка формата JSON через стандартный пакет encoding/json. В отличие от многих других языков, где требуется установка сторонних библиотек, в Go обработка JSON доступна "из коробки" и отличается высокой производительностью и строгой типизацией.
В этой статье мы подробно разберём все аспекты работы с JSON в Go: от простого парсинга до сложных сценариев с пользовательскими типами и потоковой обработкой.
Основы: кодирование и декодирование JSON
Пакет encoding/json предоставляет две основные функции: json.Marshal() для сериализации Go-структур в JSON и json.Unmarshal() для десериализации JSON обратно в структуры.
Пример: сериализация структуры в JSON
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email,omitempty"`
}
func main() {
user := User{
Name: "Иван Петров",
Age: 30,
Email: "ivan@example.com",
}
jsonData, err := json.Marshal(user)
if err != nil {
fmt.Println("Ошибка сериализации:", err)
return
}
fmt.Println(string(jsonData))
// Вывод: {"name":"Иван Петров","age":30,"email":"ivan@example.com"}
}
Пример: десериализация JSON в структуру
func main() {
jsonString := `{"name":"Анна Смирнова","age":25,"email":"anna@example.com"}`
var user User
err := json.Unmarshal([]byte(jsonString), &user)
if err != nil {
fmt.Println("Ошибка десериализации:", err)
return
}
fmt.Printf("Имя: %s, Возраст: %d, Email: %s\n", user.Name, user.Age, user.Email)
}
Теги структур (Struct Tags)
Теги структур в Go позволяют управлять тем, как поля будут сериализоваться в JSON. Это мощный механизм для настройки имён полей, пропуска пустых значений и других опций.
Основные опции тегов:
json:"name"— задаёт имя поля в JSONjson:"-"— полностью исключает поле из JSONjson:"name,omitempty"— пропускает поле, если оно содержит нулевое значение (0, "", false, nil)json:"name,string"— принудительно преобразует числовое поле в строку
Пример с различными тегами:
type Product struct {
ID int `json:"id"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
Price float64 `json:"price,string"`
SecretKey string `json:"-"`
}
func main() {
product := Product{
ID: 101,
Title: "Ноутбук",
Description: "",
Price: 899.99,
SecretKey: "sk-12345",
}
jsonData, _ := json.MarshalIndent(product, "", " ")
fmt.Println(string(jsonData))
// Вывод:
// {
// "id": 101,
// "title": "Ноутбук",
// "price": "899.99"
// }
}
Работа с произвольными JSON-данными (interface{})
Иногда структура JSON-данных заранее неизвестна. В таких случаях можно использовать тип interface{} или map[string]interface{}.
func main() {
jsonString := `{"name":"Тест","values":[1,2,3],"active":true,"metadata":{"version":2}}`
var data map[string]interface{}
err := json.Unmarshal([]byte(jsonString), &data)
if err != nil {
fmt.Println("Ошибка:", err)
return
}
// Доступ к значениям с приведением типов
name := data["name"].(string)
values := data["values"].([]interface{})
active := data["active"].(bool)
metadata := data["metadata"].(map[string]interface{})
version := metadata["version"].(float64) // JSON числа всегда float64
fmt.Printf("Имя: %s, Активен: %t, Версия: %.0f\n", name, active, version)
for i, v := range values {
fmt.Printf("Значение %d: %v\n", i, v)
}
}
Потоковая обработка JSON
Для работы с большими JSON-файлами или потоками данных Go предоставляет json.Decoder и json.Encoder. Они позволяют обрабатывать данные без загрузки всего содержимого в память.