Go语言中JSON的反序列化规则

Unmarshal 解析

go 复制代码
func Unmarshal(data []byte, v any) error

Unmarshal 解析 JSON 编码的数据,并将结果存储在 v 指向的值中。如果 v 为 nil 或不是指针,Unmarshal 返回一个 InvalidUnmarshalError 错误。

Unmarshal 使用与 Marshal 相反的编码,根据需要分配 maps、slices 和 pointers,附加以下规则:

  • 为了将 JSON 反序列化为指针,Unmarshal 首先处理 JSON 为 JSON 字面值 null 的情况。在那种情况下,Unmarshal 将指针设置为 nil。否则,Unmarshal 会将 JSON 反序列化为指针所指向的值。如果指针为 nil,Unmarshal 为它分配一个新值。

  • 为了将 JSON 反序列化为实现了 Unmarshaler 接口的值,Unmarshal 会调用该值的 UnmarshalJSON 方法,包括当输入是一个 JSON null 时。否则,如果该值实现了 encoding.TextUnmarshaler 并且输入是一个 JSON 引号字符串,Unmarshal 使用该字符串的未引用形式调用该值的 UnmarshalText 方法。

  • 为了将 JSON 反序列化为结构体,Unmarshal 将传入的对象键与 Marshal 使用的键匹配(是结构字段名还是它的标签),首选精确匹配,但也接受不区分大小写的匹配。默认情况下,没有对应结构字段的对象键将被忽略(参见 Decoder.DisallowUnknownFields 作为一种选择)。

  • 为了将 JSON 反序列化为接口值,Unmarshal 在接口值中存储以下之一:

    • bool,对应 JSON 布尔值
    • float64,对应 JSON 数字
    • string,对应 JSON 字符串
    • []interface{},对应 JSON 数组
    • map[string]interface{},对应 JSON 对象
    • nil,对应 JSON null
  • 为了将 JSON 数组反序列化为切片,Unmarshal 将切片长度重置为零,然后将每个元素追加到切片。作为一个特殊情况,为了将一个空的 JSON 数组反序列化为切片,Unmarshal 用一个新的空切片替换该切片。

  • 为了将 JSON 数组反序列化为 Go 数组,Unmarshal 将 JSON 数组元素解码为相应的 Go 数组元素。如果 Go 数组小于 JSON 数组,额外的 JSON 数组元素将被丢弃。如果 JSON 数组小于 Go 数组,额外的 Go 数组元素将设置为零值。

  • 为了将 JSON 对象反序列化为 map,Unmarshal 首先确定要使用的 map。如果 map 为 nil,Unmarshal 分配一个新的 map。否则,Unmarshal 重用现有的 map,保留现有的条目。然后,Unmarshal 将来自 JSON 对象的键值对存储在 map 中。map 的键类型必须是任何字符串类型,整数,实现 json.Unmarshaler,或实现 encoding.TextUnmarshaler。

  • 如果 JSON 编码的数据包含语法错误,Unmarshal 返回一个 SyntaxError。

  • 如果 JSON 值不适用于给定的目标类型,或者 JSON 数字溢出目标类型,Unmarshal 跳过该字段并尽其所能完成反序列化。如果没有遇到更严重的错误,Unmarshal 返回描述最早的这种错误的 UnmarshalTypeError。无论如何,不能保证在有问题的字段之后的所有剩余字段都会被反序列化到目标对象中。

  • JSON null 值反序列化为接口、map、指针或切片时,通过将该 Go 值设置为 nil 来完成。因为在 JSON 中,null 经常用来表示"不存在",所以将 JSON null 反序列化为任何其他 Go 类型对该值没有影响,也不会产生错误。

  • 当反序列化带引号的字符串时,无效的 UTF-8 或无效的 UTF-16 替代对不被视为错误。相反,它们被替换为 Unicode 替代字符 U+FFFD。