【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 时,切片的初始容量无意义,不用提前指定,直接声明即可

442

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



