JSON
Vi sono molte funzioni per il trattamento di dati JSON (JavScript Object Notation), poichè è un formato molto usato nella comunicazione dati tra un server web e un browser.
Le due funzioni principali sono:
Marshal
- codifica da Go a JSONUnmarshal
- codifica da JSON a Go
E' possibile codificare dati singoli, collezioni (arrays, slices, maps) e structs.
Nel marshalling di struct i nomi dei campi diventano di default i tag dei dati JSON.
Ma è possibile commentare ogni campo di struct indicando il tag JSON che deve avere.
(470json.go):
package main
import "encoding/json"
import "fmt"
import "os"
// Strutture per l'esercizio
type Response1 struct {
Page int
Fruits []string
}
// I tag forniscono la rappresentazione JSON
// minuscole anzichè maiuscole
type Response2 struct {
Page int `json:"page"`
Fruits []string `json:"fruits"`
}
func main() {
// Codifica di valori singoli
bolB, _ := json.Marshal(true)
fmt.Println(string(bolB))
intB, _ := json.Marshal(1)
fmt.Println(string(intB))
fltB, _ := json.Marshal(2.34)
fmt.Println(string(fltB))
strB, _ := json.Marshal("gopher")
fmt.Println(string(strB))
// Codifica di slice
slcD := []string{"apple", "peach", "pear"}
slcB, _ := json.Marshal(slcD)
fmt.Println(string(slcB))
// Codifica di mappa
mapD := map[string]int{"apple": 5, "lettuce": 7}
mapB, _ := json.Marshal(mapD)
fmt.Println(string(mapB))
// Codifica di struct
// Notare che Marsal vuole un indirizzo
res1D := &Response1{
Page: 1,
Fruits: []string{"apple", "peach", "pear"}}
res1B, _ := json.Marshal(res1D)
fmt.Println(string(res1B))
// Codifica JSON usando i tag della struct
res2D := &Response2{
Page: 1,
Fruits: []string{"apple", "peach", "pear"}}
res2B, _ := json.Marshal(res2D)
fmt.Println(string(res2B))
// Struttura dati generica in formato JSON
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
// Map che conterrà i dati decodificati
var dat map[string]interface{}
// Decodifica con controllo errori
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
// Occorre compiere il cast dei valori della map
// Il campo num è un float
num := dat["num"].(float64)
fmt.Println(num)
// I dati innestati richiedono una serie di cast
strs := dat["strs"].([]interface{})
str1 := strs[0].(string)
fmt.Println(str1)
// I dati JSON possono essere decodificati in
// un'interfaccia fornita
str := `{"page": 1, "fruits": ["apple", "peach"]}`
// Una struct è un'interfaccia
res := Response2{}
json.Unmarshal([]byte(str), &res)
fmt.Println(res)
fmt.Println(res.Fruits[0])
// Si può mandare la codifica JSON direttamente a stdout
// Occorre generare un codificatore apposito
enc := json.NewEncoder(os.Stdout)
d := map[string]int{"apple": 5, "lettuce": 7}
enc.Encode(d)
}
Lo unmarshalling si compie con due argomenti:
- una slice di byte, che è il formato JSON
- l'indirizzo della destinazione Go, che può essere:
- una map
- una struct
Nel caso di una map ogni dato recuperato deve subire un cast al tipo appropriato, ponendo particolare attenzione a compiere il cast anche dei dati innestati.
Nel caso di una struct, i tipi sono automaticamente convertiti nei tipi dei campi della struct riceventi.