JSON in Struct Go
Genera struct Go da JSON
Input JSON
Output Go
Cos'è la conversione da JSON a struct Go?
La conversione da JSON a Go trasforma dati JSON grezzi in definizioni di tipo Go che funzionano con il pacchetto encoding/json della libreria standard di Go. Go è tipizzato staticamente, quindi ogni campo JSON richiede un campo struct corrispondente con il tipo corretto e un tag struct che indica al serializzatore quale chiave JSON associare. Scrivere queste definizioni a mano per risposte API grandi o profondamente annidate è lento e soggetto a errori.
Il pacchetto encoding/json, presente nella specifica Go fin dalla versione 1.0, usa la reflection per abbinare le chiavi JSON ai campi struct esportati. L'abbinamento è insensibile alle maiuscole per impostazione predefinita, ma i tag struct json espliciti sono la pratica standard perché eliminano ambiguità e permettono di usare la convenzione PascalCase di Go mentre il JSON rimane in camelCase o snake_case. Un convertitore automatizza tutto questo: legge il JSON, deduce i tipi Go dai valori e produce definizioni struct con i tag corretti.
Il sistema di tipi di Go si mappa in modo pulito su JSON. Le stringhe diventano string, i booleani diventano bool, gli interi diventano int e i numeri in virgola mobile diventano float64. Gli oggetti JSON annidati diventano struct con nome separati, e gli array diventano slice. L'unica lacuna riguarda null: Go non ha un tipo nullable universale, quindi i valori null diventano tipicamente tipi puntatore (*string, *int) o interface{}. Un generatore gestisce tutto questo in pochi millisecondi.
Perché usare un convertitore da JSON a Go?
Definire struct Go da JSON a mano significa contare le parentesi graffe, indovinare i tipi e riscrivere i tag ogni volta che l'API cambia. Un convertitore elimina questa fatica.
Casi d'uso di JSON in struct Go
Mappatura dei tipi da JSON a Go
Il pacchetto encoding/json segue regole specifiche quando associa i valori JSON ai tipi Go. La tabella seguente mostra la mappatura predefinita e le alternative comuni. La colonna "Default" è ciò che la maggior parte dei generatori produce. La colonna "Alternativa" mostra i tipi che potresti scegliere in base ai tuoi requisiti, come int64 per ID grandi o tipi puntatore per campi nullable.
| Tipo JSON | Esempio | Default | Alternativa |
|---|---|---|---|
| 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{} |
Riferimento ai tag struct JSON di Go
I tag struct controllano come encoding/json serializza e deserializza i campi. Il tag json è di gran lunga il più comune, ma puoi combinarlo con altri tag (db, yaml, xml) sullo stesso campo. La sintassi del tag è una stringa delimitata da backtick dopo il tipo del campo. Ecco le opzioni del tag json supportate da encoding/json.
| Tag | Comportamento | Caso d'uso |
|---|---|---|
| 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 vs json.NewDecoder
Go offre due modi per decodificare JSON: json.Unmarshal per slice di byte e json.NewDecoder per stream io.Reader. Entrambi usano le stesse regole dei tag struct, ma differiscono nel momento in cui usarli.
Esempi di codice
Questi esempi mostrano come usare struct Go generate da JSON in programmi reali, oltre a come generarle da altri linguaggi. Gli esempi Go usano encoding/json dalla libreria standard.
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
}