本文整理Go语言新手处理JSON反序列化时必踩的5大坑点,每个坑都附上真实代码案例和避坑指南。
本文精华:
| 问题现象 | 检查点 |
|---|---|
| 字段值为零值 |
1. 首字母是否大写 2. JSON标签是否正确 |
| 部分字段丢失 | JSON key与结构体标签是否严格匹配 |
| 数值类型异常 | JSON数值是否为整数型数字 |
| 循环产生重复数据 | 是否在循环内重复使用变量指针 |
一、字段首字母必须大写(可见性规则)
type User struct {
id int // 小写开头字段
Name string // 大写开头字段
}
反序列化后:
user := User{}
json.Unmarshal(data, &user)
fmt.Println(user.id) // 输出 0(未成功赋值)
原理:Go语言通过首字母大小写控制字段可见性,encoding/json 包只能访问可导出的(大写开头的)结构体字段
解决方法:
type User struct {
ID int `json:"id"` // 首字母大写,通过标签映射小写key
Name string `json:"name"`
}
二、JSON标签与数据结构不匹配
type Product struct {
SKU string `json:"product_id"` // 标签名与JSON字段不一致
Price float64
}
此时SKU在反序列化时,是不能被正确赋值的,除非刚好有数据能对应 product_id
解决方法:
type Product struct {
SKU string `json:"sku"` // 保持标签与JSON键名一致
Price float64 `json:"price"`
}
三、数据类型不匹配(静默失败)
type Config struct {
Status int `json:"status"`
}
// JSON数据:{"status": "1"} (字符串类型数值)
此时,json反序列化就会报错,无法转化到int类型!!
解决方法:
// JSON数据:{"status": 1} (整数类型数值)
四、大小写敏感陷阱
type Account struct {
Email string `json:"email"` // 标签全小写
}
// JSON数据:{"Email": "test@example.com"} (首字母大写)
反序列化后Email字段为空值
解决方法:
// 使用 {"email": "test@example.com"}
五、循环内反序列化的致命坑(痛彻心扉,当时给编者找傻了。附真实案例)
type Person struct {
Name string `json:"name"`
// ....
SonConfig string `json:"config"`
Son []*Person `json:"son"`
}
var son []*Person // 在循环外定义
for _, data := range jsonData {
err := json.Unmarshal([]byte(data.SonConfig), &son)
if err != nil {
log.Println(err)
continue
}
data.Son = append(data.Son, son...) // 将 son 的地址添加到 data.Son 中
}
此时,data.Son里的数据是有可能出错。由于 son 本身在每次反序列化时都被重写了,最终 data.Son 中实际上会包含最后一次解析的结果。
解决方法:
type Person struct {
Name string `json:"name"`
SonConfig string `json:"config"`
Son []*Person `json:"son"`
}
for _, data := range jsonData {
var son []*Person // 在循环内定义新的 son 切片
err := json.Unmarshal([]byte(data.SonConfig), &son)
if err != nil {
log.Println(err)
continue
}
data.Son = append(data.Son, son...) // 使用 ... 来展开 son 切片
}
&spm=1001.2101.3001.5002&articleId=146479507&d=1&t=3&u=94ef897e37de4a5fa7218087a5c45d34)
1737

被折叠的 条评论
为什么被折叠?



