使用 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: %dnok:%tn", userid, ok)
fmt.println() // spliter
postids, ok := m["id"].([]int64)
fmt.printf("post_ids: %vnok:%tn", postids, ok)
}
只是编组和解组返回结构,因此预计会返回相同的值!
不幸的是,这没有发生,上面的代码输出
// result
id: 0
ok:false
post_ids: []
ok:false
当我看到这个输出时,我?问题可能出在类型转换上,所以我去检查这些接口有什么类型
fmt.printf("id: %tn", m["id"])
fmt.printf("post_ids: %tn", m["post_ids"])
// result
id: float64
post_ids: []interface {}
所以我们可以看到,json 将 int64 解析为 float64,这会导致读取数据时出现问题。
实际上有两种方法可以解决这个问题
? 解决方案01(困难)
使用float64的类型断言,注意[]interface{}不能立即映射到[]float64,所以我们必须迭代每个元素并将其转换
// parse userid
userid, _ := m["id"].(float64)
fmt.printf("id: %fn", 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: %vn", postids)
// result
id: 1.000000
post_ids: [1 2 3]
? 解决方案02(简单方法)
将其解析回结构体
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不是更好吗?
这取决于情况,您并不总是想创建一个结构体来从结构体中读取单个属性,所以正确的答案是——这取决于情况!
我想今天的文章就到此为止了,祝你学到一些新东西,我的地鼠伙伴?。