Работа с JSON может показаться простой и понятной: у вас есть некоторая структура, вы можете изменить ее на JSON — общий унифицированный язык и вернуться к своей структуре. Просто, правда? ?
Ну да, но это до тех пор, пока вы не столкнетесь со странным поведением функций Marshal/Unmarshal.
Все началось, когда я пытался прочитать закодированную полезную нагрузку из токена JWT. Ниже приведен пример, демонстрирующий проблему
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) }
Просто маршалинг и демаршалинг структуры, поэтому ожидается, что она вернет одно и то же значение!
К сожалению, этого не произошло, код выше выводит
// Result id: 0 Ok:false post_ids: [] Ok:false
Как только я увидел этот результат, я ? проблема может быть в преобразованиях типов, поэтому я пошел проверить, какие типы имеют эти интерфейсы
fmt.Printf("id: %T\n", m["id"]) fmt.Printf("post_ids: %T\n", m["post_ids"])
// Result id: float64 post_ids: []interface {}
Итак, как мы видим, JSON анализирует int64 как float64, что приводит к проблемам при чтении данных.
На самом деле существует два способа решить эту проблему
Используйте утверждения типа float64. Обратите внимание, что []interface{} нельзя сразу сопоставить с []float64, поэтому нам приходится перебирать каждый элемент и конвертировать его
// 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]
Разберите его обратно в структуру
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)
Конечно, вы можете подумать: зачем нам вообще использовать Решение 01, разве Решение 02 не лучше?
Ну, это зависит от того, вы не всегда хотите создавать структуру для чтения одного атрибута из структуры, поэтому правильный ответ: — Это зависит!
Думаю, на сегодня это все, желаю тебе узнать что-то новое, мой друг-суслик?.
Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.
Copyright© 2022 湘ICP备2022001581号-3