【golang】json.Unmarshal(data []byte, v any)

【golang】json.Unmarshal(data []byte, v any)

json.Unmaeshal(data []byte , v any)
只接受[]byte, 如果是其他 需要强转才能传进去
步骤:
1.接收转好的「字节切片」([]byte)(本质是 JSON 文本的字节形式)
2.解析器开始「逐字节解析」这个 JSON 文本,识别出这是一个JSON 数组,数组里的每一项都是字符串
3.解析成功 → 把 JSON 数组里的每一个字符串元素,逐个放进你的 Images 切片([]string)里 (我准备的啥类型就转化成啥类型)

		//解析图片
		Images := make([]string, 0) //初始化空字符串
		if content.Images != "" {
			//就是把库中这个按照json格式存储的字符串数组图片 解析为 Go的字符串切片[]string
			if err := json.Unmarshal([]byte(content.Images), &Images); err != nil {
				//如果为空返回空
				Images = make([]string, 0)
				//为什么要再写一遍空字符串?
				//json.Unmarshal 解析失败 变量Inages的值会变成脏数据  这里就是解析失败的重置
				//脏数据: 比如解析一半才成功的  其中成功的这一部分依旧会放进Images中  这样前端就显示不完整 形成脏数据
				
				//也可以这么写  Images = []string{} // 直接赋值空切片,和make([]string,0)完全等价
			}
		}

更优写法:

		// 解析图片 (最优,一行兜底,无冗余)
		var Images []string //初始变量 初始值是nil切片
		if content.Images != "" {
			_ = json.Unmarshal([]byte(content.Images), &Images)
		}
		//解析成功 Images被赋值成正确的切片 解析失败json.Unmarshal 不会修改变量,Images 保持 nil
		//"_" : 我们已经通过「nil 切片的特性」,天然处理了解析失败的情况 → 失败了就是 nil,业务上等价于空切片,不需要额外处理错误 (除非需要记录日志)

为什么这里解析失败不会改变变量?

//都是[]string字符串切片 都是len(Images)=0 、 cap(Images)=0 ,内存占用为 0
//区别:
Images := make([]string, 0) //声明+初始化赋值
//初始值: 手动创建的[空切片] 这个切片不是nil,它在内存中有自己的地址(就是说有一块内容是分配给它的 但是啥也没放 0也没有)
var Images []string //只声明不赋值
//初始值: Go语言的默认零值 -> nil (这个就是 nil切片)
//它再内存中没有分配任何空间 没有内存地址

json.Unmarshal 这个函数的【官方底层执行规则】:

针对「值类型 / 已分配内存的引用类型」:
解析成功 → 把完整的正确数据,完整覆盖写入变量,变量最终是正确值
解析失败 → 解析器会「边解析、边写入」,遇到错误才停止,已经解析成功的部分数据会被写入变量,未解析的部分丢弃;变量最终的值 = 原始值 + 解析成功的部分数据 → 产生脏数据
针对「未分配内存的 nil 引用类型」:
解析成功 → 解析器会先为变量自动分配内存空间,再把完整的正确数据写入变量;
解析失败 → 解析器连内存空间都没有,想写数据也没地方写,变量会「一丝一毫都不变化」,严格保持调用前的原始 nil 值 → 绝对干净,零脏数据
这个规则是 Go 标准库encoding/json包的官方固定规则,没有例外,所有 Go 项目都遵循这个规则

那为什么之前的 Images := make([]string, 0) 就可以在解析失败的时候给Images赋值脏数据?

Images := make([]string, 0) // 初始值:【非nil的空切片】,内存地址已分配
if content.Images != "" {
    if err := json.Unmarshal([]byte(content.Images), &Images); err != nil {
        Images = make([]string, 0) // 必须手动重置,否则有脏数据
    }
}

        Images := make([]string,0) 是手动创建了一个空切片,这个切片不是nil,它在内存中有自己的地址,是一个「实实在在的切片对象」
        当解析失败时,json.Unmarshal虽然不会「完整赋值」,但是会把解析过程中匹配成功的部分数据,写入这个「已存在的切片对象」中 最终结果:切片里残留「半解析的脏数据」

而:

		var Images []string //初始化 → 原始值 = nil 切片
		if content.Images != "" {
			_ = json.Unmarshal([]byte(content.Images), &Images)
		}
		

        var Images []string 是nil 切片,这个切片在内存中「没有分配任何空间」,也「没有内存地址」,就是一个纯粹的零值
        当json.Unmarshal解析失败, json.Unmarshal 遵守规则 → 完全不修改Images变量
        当解析成功时,json.Unmarshal 会自动为 nil 切片分配内存,并把正确的解析结果写入进去
        最终结果:要么是 nil,要么是 正确的切片,永远不会出现「半解析的脏数据」

总结:
var Images []string → 无内存地址 → 解析失败 → 干干净净的 nil,一丝不变
Images := make([]string, 0) → 有内存地址 → 解析失败 → 大概率写入「脏数据」

还需要注意的是:

Images := make([]string,0,10) // 初始容量10
json.Unmarshal([]byte(`["a","b"]`), &Images)
// 解析后:Images = ["a","b"],容量变成2,不是10

解析 JSON 时,切片的初始容量无意义,不用提前指定,直接声明即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~小鹿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值