【GO】json反序列化结构体的坑!!!(附解决方案)

本文整理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 切片
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值