Модульні уроки (5/5)
`кодування/json`
encoding/json — це канонічний пакет для серіалізації структур Go у JSON і назад. Знаючи його умовності та підводні камені, ви заощаджуєте години налагодження API та конфігураційних файлів.
Маршал і Немаршал
Дві основні функції:
data, err := json.Marshal(v) // Go → []byte JSON
err = json.Unmarshal(data, &v) // JSON → Go (pass a pointer!)type User struct {
Name string
Email string
}
u := User{Name: "Ada", Email: "ada@example.com"}
b, _ := json.Marshal(u)
fmt.Println(string(b))
// {"Name":"Ada","Email":"ada@example.com"}
var back User
_ = json.Unmarshal(b, &back)Для виводу з відступом (читається людиною) використовуйте json.MarshalIndent(v, "", " ").
Лише експортовані поля
json.Marshal серіалізує лише експортовані поля (Великий регістр). Приватні поля ігноруються мовчки:
type U struct {
Name string // exported → serialized
age int // private → ignored
}Теги структури: керування назвою та параметрами
Теги json:"..." керують іменем, пропуском і типами виводу:
type User struct {
Name string `json:"name"` // rename
Email string `json:"email,omitempty"` // omit if zero value
Private string `json:"-"` // never serialized
ID int `json:"id,string"` // number as string
}Найбільш використовувані варіанти:
,omitempty— пропускає поле, якщо воно є нульовим значенням (0, "", нуль, порожній фрагмент/карта).,-— ніколи не серіалізується/десеріалізується.,string— обертає числа/bools як рядки (корисно для ідентифікаторів JS).
Декодер/Кодер для потоків
Під час роботи з io.Reader/io.Writer (тіло HTTP, великі файли) використовуйте Decoder та Encoder замість завантаження всього в пам’ять:
dec := json.NewDecoder(resp.Body)
var users []User
if err := dec.Decode(&users); err != nil {
return err
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
_ = enc.Encode(users)Decoder також підтримує dec.Token() для потокового аналізу по частинах і dec.DisallowUnknownFields() для відхилення JSON із неочікуваними ключами (корисно для перевірки введення).
Загальні карти та any
Якщо ви не знаєте схему, десеріалізуйте в map[string]any:
var v map[string]any
_ = json.Unmarshal(data, &v)
fmt.Println(v["name"])Значення матимуть динамічні типи (string, float64 для чисел, []any, map[string]any, bool, nil).
Поширені помилки
- Забути
&:json.Unmarshal(data, v)нічого не заповнює; вам потрібен&v. - Декодування структур із нульовими полями: щоб уникнути паніки, перевірте
errПЕРЕД читанням полів. - Несумісні типи: десеріалізація числа в рядок або навпаки повертає
*json.UnmarshalTypeError.
вправи
Серіалізуйте структуру u в JSON за допомогою json.Marshal і надрукуйте результат у вигляді рядка.
Рішення доступне після 3 спроб
Десеріалізуйте `{"Name":"Ada"}` у структуру U за допомогою json.Unmarshal і надрукуйте його.
Рішення доступне після 3 спроб
Чи включено поле `name string` (нижній регістр) структури до json.Marshal?
type U struct {
name string
}
b, _ := json.Marshal(U{name: "Ada"})
fmt.Println(string(b))