Go的json.Unmarshal要求结构体字段首字母大写,因反射仅能访问导出字段,小写字段被静默忽略;类型须严格匹配,嵌套结构需分层定义导出字段并配json标签。

Go 的 json.Unmarshal 是解析 JSON 的唯一标准入口,但它不是“开箱即用”的万能函数——字段大小写、类型不匹配、嵌套结构松散都会导致静默失败或 panic,必须按规则来。
结构体字段必须首字母大写才能被 json.Unmarshal 识别
小写字段(如 name string)在反序列化时会被完全忽略,因为 json 包依赖 reflect 访问字段,而 Go 的反射无法读取未导出(小写)成员。
- 错误写法:
type User { name string `json:"name"` }→ 解析后name始终为空字符串 - 正确写法:
type User { Name string `json:"name"` }→ 字段可被反射访问 - 如果字段确实需私有(比如只允许内部修改),可用
json:"-"显式忽略,而不是靠小写“隐藏”
数字字段遇到字符串值会直接报错:json: cannot unmarshal string into Go struct field
Go 默认不做类型柔化,"123" 是字符串,不能自动转成 int;"true" 也不能转 bool。错误信息明确指向字段名和类型冲突点。
- 常见场景:前端传参习惯把所有值当字符串发,或数据库导出 JSON 时数字被引号包裹
- 临时解法:把字段类型改为
json.RawMessage,后续手动解析并容错转换(用strconv.Atoi或类型断言) - 长期解法:为结构体实现
UnmarshalJSON方法,在其中对特定字段做字符串→数字的 fallback 处理
解析嵌套对象或数组时,结构体字段类型必须严格匹配
JSON 中的 {"items": [{"id": 1}]} 要求 Go 结构体中 Items 字段类型是 []Item,而不是 Item 或 map[string]interface{},否则会报类型不匹配错误。
立即学习“go语言免费学习笔记(深入)”;
- 嵌套对象:用内嵌结构体,标签照常加
json:"xxx" - 数组:字段类型必须是切片,如
[]string、[]Product - 混合数组(不同结构混排):不能用固定结构体,得用
[]interface{}+ 类型断言,或改用json.RawMessage延迟解析 - 空数组
[]和null行为不同:前者解到[]T是空切片;后者默认会报错,需配合omitempty或自定义 Unmarshal 处理
用 map[string]interface{} 解析动态 JSON 时要注意 float64 陷阱
JSON 数字(无论整数还是小数)在 map[string]interface{} 中一律转为 float64,直接断言 int 会 panic。
- 安全取整数:
int(data["count"].(float64)),但要先检查是否为float64类型 - 更稳妥方式:
v, ok := data["count"]; if ok { if f, isFloat := v.(float64); isFloat { count := int(f) } } - 嵌套访问需逐层断言:
data["user"].(map[string]interface{})["id"].(float64),链式写法易崩,建议封装辅助函数 - 如果只是模板渲染或日志打印,
map[string]interface{}足够;但涉及计算、校验、存储,仍应尽早转为强类型结构体
最易被忽略的是:json.Unmarshal 不会自动跳过未知字段,也不会把空字符串转成零值——它只做精确映射。所谓“灵活解析”,其实是靠你主动放弃默认逻辑,用 json.RawMessage 或自定义 UnmarshalJSON 把控制权拿回来。


















