Trabalhar com JSON pode parecer simples e claro, você tem alguma estrutura, pode alterá-la para JSON - uma linguagem geral unificada e de volta à sua estrutura. Simples, certo? ?
Bem, sim, mas isso é até você encontrar algum comportamento estranho das funções Marshal / Unmarshal.
Tudo começou quando eu estava tentando ler o payload codificado de um token JWT, abaixo está um exemplo que demonstra o 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) }
Apenas empacotando e desempacotando a estrutura, então espera-se que retorne o mesmo valor!
Infelizmente, isso não aconteceu, o código acima gera
// Result id: 0 Ok:false post_ids: [] Ok:false
Assim que vi esse resultado, eu ? o problema pode ser com conversões de tipo, então fui verificar quais tipos essas interfaces possuem
fmt.Printf("id: %T\n", m["id"]) fmt.Printf("post_ids: %T\n", m["post_ids"])
// Result id: float64 post_ids: []interface {}
Então, como podemos ver, JSON analisou int64 como float64, o que leva a problemas na leitura dos dados.
Na verdade, existem duas maneiras de corrigir esse problema
Use asserções de tipo float64. Observe que a []interface{} não pode ser mapeada imediatamente para []float64, então temos que iterar cada elemento e convertê-lo
// 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]
Analisar de volta para uma estrutura
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)
Claro, você pode pensar, por que deveríamos usar a Solução 01, a Solução 02 não é melhor?
Bem, depende, você nem sempre deseja criar uma estrutura para ler um único atributo de uma estrutura, então a resposta correta é - Depende!
Acho que é tudo para o artigo de hoje, gostaria que você aprendesse algo novo, meu colega esquilo?.
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3