Trabajar con JSON puede parecer simple y claro, tiene alguna estructura, puede cambiarla a JSON: un lenguaje unificado general y volver a su estructura. Sencillo ¿verdad? ?
Bueno, sí, pero eso es hasta que encuentres un comportamiento extraño en las funciones Marshal/Unmarshal.
Todo comenzó cuando intentaba leer la carga útil codificada de un token JWT. A continuación se muestra un ejemplo que demuestra el problema
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) }
Simplemente ordenando y desordenando la estructura, ¡por lo que se espera que devuelva el mismo valor!
Desafortunadamente, esto no sucedió, el código anterior genera
// Result id: 0 Ok:false post_ids: [] Ok:false
Una vez que vi ese resultado, ¿yo? el problema podría estar en las conversiones de tipos, así que fui a comprobar qué tipos tienen estas interfaces
fmt.Printf("id: %T\n", m["id"]) fmt.Printf("post_ids: %T\n", m["post_ids"])
// Result id: float64 post_ids: []interface {}
Como podemos ver, JSON ha analizado int64 como float64, lo que genera problemas al leer los datos.
En realidad, hay dos formas de solucionar este problema
Utilice afirmaciones de tipo de float64. Tenga en cuenta que []interfaz{} no se puede asignar de inmediato a []float64, por lo que tenemos que iterar cada elemento y convertirlo
// 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]
Analizarlo nuevamente en una estructura
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)
Por supuesto, podrías pensar, ¿por qué deberíamos usar la Solución 01? ¿No es mejor la Solución 02?
Bueno, depende, no siempre deseas crear una estructura para leer un solo atributo de una estructura, por lo que la respuesta correcta es: ¡Depende!
Creo que eso es todo por el artículo de hoy, ¿te gustaría que aprendieras algo nuevo, amigo mío?.
Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.
Copyright© 2022 湘ICP备2022001581号-3