JSON to Go Struct
Генерація структур Go з JSON
Введення JSON
Виведення Go
Що таке конвертація JSON у структури Go?
Конвертація JSON у структури Go перетворює сирі JSON-дані на визначення типів Go, що працюють із пакетом encoding/json зі стандартної бібліотеки Go. Go є статично типізованою мовою, тому кожне JSON-поле потребує відповідного поля структури з правильним типом і тегом, який повідомляє серіалізатору, який JSON-ключ відображати. Написання таких визначень вручну для великих або глибоко вкладених відповідей API є повільним і схильним до помилок.
Пакет encoding/json, визначений у специфікації Go починаючи з Go 1.0, використовує рефлексію для відповідності JSON-ключів до експортованих полів структур. Відповідність за замовчуванням нечутлива до регістру, але явні json-теги структур є стандартною практикою — вони усувають неоднозначність і дозволяють використовувати конвенцію PascalCase у Go, тоді як JSON залишається у camelCase або snake_case. Конвертер автоматизує це: зчитує ваш JSON, визначає типи Go за значеннями та виводить визначення структур з правильними тегами.
Система типів Go добре відображається на JSON. Рядки стають string, булеві значення — bool, цілі числа — int, а числа з плаваючою крапкою — float64. Вкладені JSON-об'єкти стають окремими іменованими структурами, а масиви — зрізами. Єдина прогалина — null: Go не має універсального типу, що допускає null, тому значення null зазвичай стають вказівними типами (*string, *int) або interface{}. Генератор обробляє все це за мілісекунди.
Навіщо використовувати конвертер JSON у структури Go?
Визначення структур Go з JSON вручну означає підрахунок дужок, здогадки про типи та переписування тегів щоразу, коли API змінюється. Конвертер усуває це тертя.
Сценарії використання JSON to Go Struct
Таблиця відповідності типів JSON та Go
Пакет encoding/json дотримується конкретних правил при відображенні JSON-значень на типи Go. Таблиця нижче показує стандартне відображення та поширені альтернативи. Стовпець «За замовчуванням» — це те, що виробляє більшість генераторів. Стовпець «Альтернатива» показує типи, які ви можете обрати відповідно до ваших вимог, наприклад int64 для великих ID або вказівні типи для полів, що допускають null.
| Тип JSON | Приклад | За замовчуванням | Альтернатива |
|---|---|---|---|
| string | "hello" | string | string |
| number (integer) | 42 | int | int64 |
| number (float) | 3.14 | float64 | float64 |
| boolean | true | bool | bool |
| null | null | interface{} | *string / *int |
| object | {"k": "v"} | struct | struct |
| array of strings | ["a", "b"] | []string | []string |
| array of objects | [{"id": 1}] | []Item | []Item |
| mixed array | [1, "a"] | []interface{} | []interface{} |
Довідник тегів структур Go JSON
Теги структур керують тим, як encoding/json серіалізує та десеріалізує поля. Тег json є найпоширенішим, але ви можете поєднувати його з іншими тегами (db, yaml, xml) в одному полі. Синтаксис тегу — це рядок у зворотних лапках після типу поля. Нижче наведено параметри json-тегу, які підтримує encoding/json.
| Тег | Поведінка | Сценарій використання |
|---|---|---|
| json:"name" | Maps struct field to JSON key "name" | Always generated |
| json:"name,omitempty" | Omits field from output if zero value | Optional fields |
| json:"-" | Field is never serialized or deserialized | Internal fields |
| json:"name,string" | Encodes int/bool as JSON string | String-encoded numbers |
json.Unmarshal та json.NewDecoder
Go надає два способи декодування JSON: json.Unmarshal для байтових зрізів і json.NewDecoder для потоків io.Reader. Обидва використовують одні й ті самі правила тегів структур, але відрізняються тим, коли їх застосовувати.
Приклади коду
Ці приклади показують, як використовувати структури Go, згенеровані з JSON, у реальних програмах, а також як генерувати їх з інших мов. Приклади Go використовують encoding/json зі стандартної бібліотеки.
package main
import (
"encoding/json"
"fmt"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
IsActive bool `json:"is_active"`
Tags []string `json:"tags"`
}
func main() {
data := []byte(`{"id":1,"name":"Alice","email":"alice@example.com","is_active":true,"tags":["admin","editor"]}`)
var user User
if err := json.Unmarshal(data, &user); err != nil {
panic(err)
}
fmt.Println(user.Name) // → Alice
fmt.Println(user.Tags) // → [admin editor]
}// JSON response from API — this is the shape you'd convert to Go:
const res = await fetch("https://api.example.com/users/1");
const user = await res.json();
// user → { "id": 1, "name": "Alice", "email": "alice@example.com" }
// Equivalent Go struct:
// type User struct {
// ID int `json:"id"`
// Name string `json:"name"`
// Email string `json:"email"`
// }import json
def json_to_go(data: dict, name: str = "Root") -> str:
lines = [f"type {name} struct {{"]
type_map = {str: "string", int: "int", float: "float64", bool: "bool"}
for key, value in data.items():
go_type = type_map.get(type(value), "interface{}")
field = key.title().replace("_", "") # snake_case → PascalCase
lines.append(f'\t{field} {go_type} `json:"{key}"`')
lines.append("}")
return "\n".join(lines)
data = json.loads('{"user_name": "Alice", "age": 30, "verified": true}')
print(json_to_go(data))
# type Root struct {
# UserName string `json:"user_name"`
# Age int `json:"age"`
# Verified bool `json:"verified"`
# }package main
import (
"encoding/json"
"fmt"
"strings"
)
type Event struct {
Type string `json:"type"`
Payload string `json:"payload"`
}
func main() {
stream := strings.NewReader(`{"type":"click","payload":"btn-1"}
{"type":"scroll","payload":"page-2"}`)
dec := json.NewDecoder(stream)
for dec.More() {
var ev Event
if err := dec.Decode(&ev); err != nil {
break
}
fmt.Printf("%s: %s\n", ev.Type, ev.Payload)
}
// → click: btn-1
// → scroll: page-2
}