Maison >développement back-end >Golang >Le mystère de la conversion JSON de IntTo Float64
Travailler avec JSON peut sembler simple et clair, vous avez une structure, vous pouvez la changer en JSON — Un langage général unifié et revenir à votre structure. Simple, non ? ?
Eh bien, oui, mais c'est jusqu'à ce que vous rencontriez un comportement étrange de la part des fonctions Marshal/Unmarshal.
Tout a commencé lorsque j'essayais de lire la charge utile codée à partir d'un jeton JWT. Vous trouverez ci-dessous un exemple qui illustre le problème
package main import ( "encoding/json" "fmt" ) type User struct { ID int64 `json:"id"` PostIDs []int64 `json:"post_ids"` } func main() { u := User{ ID: 1, PostIDs: []int64{1, 2, 3}, } b, err := json.Marshal(u) if err != nil { panic(err) } m := make(map[string]interface{}) if err = json.Unmarshal(b, &m); err != nil { panic(err) } userID, ok := m["id"].(int64) fmt.Printf("id: %d\nOk:%t\n", userID, ok) fmt.Println() // spliter postIDs, ok := m["id"].([]int64) fmt.Printf("post_ids: %v\nOk:%t\n", postIDs, ok) }
Il suffit de marshaler et de démarshaler la structure, donc elle devrait renvoyer la même valeur !
Malheureusement, cela ne s'est pas produit, le code ci-dessus affiche
// Result id: 0 Ok:false post_ids: [] Ok:false
Une fois que j'ai vu cette sortie, je ? le problème pourrait venir des conversions de types, alors je suis allé vérifier quels types ont ces interfaces
fmt.Printf("id: %T\n", m["id"]) fmt.Printf("post_ids: %T\n", m["post_ids"])
// Result id: float64 post_ids: []interface {}
Comme nous pouvons le voir, JSON a analysé int64 comme float64, ce qui entraîne des problèmes lors de la lecture des données.
Il existe en fait 2 façons de résoudre ce problème
Utilisez les assertions de type de float64, notez que []interface{} ne peut pas être mappée immédiatement sur []float64, nous devons donc itérer chaque élément et le convertir
// Parse UserID userID, _ := m["id"].(float64) fmt.Printf("id: %f\n", userID) fmt.Println() // spliter // Parse PostIDs postIDsArr, _ := m["post_ids"].([]interface{}) postIDs := make([]int64, len(postIDsArr)) for i, v := range postIDsArr { id, _ := v.(float64) // NOTICE: direct conversion to int64 won't work here! postIDs[i] = int64(id) } fmt.Printf("post_ids: %v\n", postIDs)
// Result id: 1.000000 post_ids: [1 2 3]
Analysez-le en une structure
b, err = json.Marshal(m) // m = map[string]interface{} if err != nil { panic(err) } var u2 User if err := json.Unmarshal(b, &u2); err != nil { panic(err) } fmt.Println(u2.ID) fmt.Println(u2.PostIDs)
Bien sûr, vous pourriez penser, pourquoi devrions-nous même utiliser la solution 01, la solution 02 n'est-elle pas meilleure ?
Eh bien, cela dépend, vous ne voulez pas toujours créer une structure pour lire un seul attribut d'une structure, donc la bonne réponse est -- Cela dépend !
Je pense que c'est tout pour l'article d'aujourd'hui, j'aimerais que tu aies appris quelque chose de nouveau, mon cher Gopher ?.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!