Working with JSON can sound simple & clear, you have some struct, you can change it to JSON — A general unified language & back to your struct. Simple right? ?
Well, yeah, but that's until you encounter some weird behavior from the Marshal / Unmarshal functions.
It all started when I was trying to read the encoded payload from a JWT token, below is an example that demonstrates the issue
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) }
Just marshaling and unmarshaling back out struct, so it's expected to return the same value!
Unfortunately, this didn't happen, the code above outputs
// Result id: 0 Ok:false post_ids: [] Ok:false
Once I saw that output, I ? the issue might be with type conversions, so I went to check what types does these interfaces have
fmt.Printf("id: %T\n", m["id"]) fmt.Printf("post_ids: %T\n", m["post_ids"])
// Result id: float64 post_ids: []interface {}
So as we can see, JSON has parsed out int64 as float64, which lead to issues upon reading the data.
There is actually 2 ways to fix this issue
Use type assertions of float64, Notice that []interface{} can't be mapped right away to []float64, so we have to iterate each element and convert it
// 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]
Parse it back to a struct
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)
Of course, you might think, why should we even use Solution 01, isn't Solution 02 better?
Well it depends, you don't always want to create a struct to read a single attribute from a struct, so the correct answer is -- It depends!
I think that's all for today's article, wish you learned something new, my fellow gopher ?.
以上是IntTo Float64 JSON转换之谜的详细内容。更多信息请关注PHP中文网其他相关文章!