Lezioni del modulo (5/5)
`encoding/json`
encoding/json è il pacchetto canonico per serializzare struct Go in JSON e viceversa. Conoscerne convenzioni e trabocchetti ti risparmia ore di debug su API e file di configurazione.
Marshal e Unmarshal
Le due funzioni principali:
data, err := json.Marshal(v) // Go → []byte JSON
err = json.Unmarshal(data, &v) // JSON → Go (passa puntatore!)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)Per output indentato (leggibile a umani) usa json.MarshalIndent(v, "", " ").
Solo campi esportati
json.Marshal serializza soltanto i campi esportati (Maiuscoli). I campi privati vengono ignorati silenziosamente:
type U struct {
Name string // esportato → serializzato
age int // privato → ignorato
}Struct tag: controllo del nome e delle opzioni
I tag json:"..." controllano nome, omissione e tipi nell'output:
type User struct {
Name string `json:"name"` // rinomina
Email string `json:"email,omitempty"` // omette se zero value
Private string `json:"-"` // mai serializzato
ID int `json:"id,string"` // numero come stringa
}Opzioni più usate:
,omitempty— omette il campo se è il zero value (0, "", nil, slice/map vuoti).,-— mai serializzato/deserializzato.,string— incapsula numeri/bool come stringhe (utile per ID JS).
Decoder/Encoder per stream
Quando lavori con io.Reader/io.Writer (HTTP body, file enormi) usa Decoder ed Encoder invece di caricare tutto in memoria:
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 supporta anche dec.Token() per parsing streaming pezzo-a-pezzo e dec.DisallowUnknownFields() per rifiutare JSON con chiavi non previste (utile per validare input).
Mappe generiche e any
Se non conosci lo schema, deserializza in map[string]any:
var v map[string]any
_ = json.Unmarshal(data, &v)
fmt.Println(v["name"])I valori avranno tipi dinamici (string, float64 per i numeri, []any, map[string]any, bool, nil).
Errori comuni
- Dimenticare
&:json.Unmarshal(data, v)non popola nulla; serve&v. - Decodare struct con campi nil: per evitare panic, controlla
errPRIMA di leggere campi. - Tipi non compatibili: deserializzare un numero in una stringa o viceversa ritorna
*json.UnmarshalTypeError.
Esercizi
Serializza la struct u in JSON con json.Marshal e stampa il risultato come stringa.
Soluzione disponibile dopo 3 tentativi
Deserializza `{"Name":"Ada"}` nella struct U con json.Unmarshal e stampala.
Soluzione disponibile dopo 3 tentativi
Il campo `name string` (minuscolo) di una struct viene incluso da json.Marshal?
type U struct {
name string
}
b, _ := json.Marshal(U{name: "Ada"})
fmt.Println(string(b))