Go解析JSON应优先用os.ReadFile+json.Unmarshal,结构体字段需大写导出并正确标注json标签;动态场景用map[string]interface{}配合类型断言;写文件用json.MarshalIndent提升可读性;时间与大数需特殊处理避免精度丢失。

用 json.Unmarshal 读取 JSON 文件内容
Go 里解析 JSON 文件最直接的方式是先读文件字节,再交给 json.Unmarshal。别直接用 json.NewDecoder 配 os.Open——虽然它支持流式解析,但对普通配置类 JSON 文件反而容易漏错、难调试。
常见错误:把结构体字段写成小写(未导出),导致反序列化后字段始终为零值;或者字段标签写错,比如写成 `json:"name"` 却忘了引号,编译不报错但运行时失效。
实操建议:
- 定义结构体时,所有需解析的字段首字母大写(导出)
- 用
`json:"field_name,omitempty"`控制键名和空值跳过逻辑 - 先用
os.ReadFile读全量内容,避免文件句柄泄漏或提前关闭 - 检查
err——json.Unmarshal失败时不会静默吞掉错误,但很多人只打印不返回,导致后续 panic
示例:
立即学习“go语言免费学习笔记(深入)”;
data, err := os.ReadFile("config.json")
if err != nil {
log.Fatal(err)
}
var cfg struct {
Port int `json:"port"`
Host string `json:"host,omitempty"`
}
if err := json.Unmarshal(data, &cfg); err != nil {
log.Fatal(err) // 别忽略这个 err
}
处理嵌套结构或动态字段用 map[string]interface{}
当 JSON 结构不确定(比如 API 返回字段随版本变化)、或顶层是对象但内部键名不固定时,硬写结构体会很累,也容易 panic。这时用 map[string]interface{} 更灵活,但要注意类型断言成本和可读性折损。
常见错误:直接对 map[string]interface{} 中的值做算术运算,不检查是否为 float64(JSON 数字默认转成 float64);或对嵌套 map 层层断言却忽略中间某层为 nil。
实操建议:
- 用类型断言 + 短变量声明组合判断,如
if port, ok := data["port"].(float64); ok { ... } - 嵌套访问前逐层检查
nil,不要连写data["a"].(map[string]interface{})["b"].(string) - 若仅偶尔需要动态字段,建议仍优先定义结构体,用
json.RawMessage延迟解析特定字段
写 JSON 文件优先用 json.MarshalIndent
生成可读 JSON 文件(比如配置导出、调试日志),别用 json.Marshal ——输出是单行无缩进,人眼难以排查字段缺失或嵌套错误。而 json.MarshalIndent 能加缩进和分隔符,调试效率高一个数量级。
JSON 即 JavaScript Object Natation,它是一种轻量级的数据交换格式,非常适合于服务器与 JavaScript 的交互。本文将快速讲解 JSON 格式,并通过代码示例演示如何分别在客户端和服务器端进行 JSON 格式数据的处理。
常见错误:写文件时忘记 os.O_CREATE | os.O_TRUNC | os.O_WRONLY 标志,导致文件为空或追加乱码;或没调用 file.Close(),在 Windows 下可能锁住文件。
实操建议:
- 用
os.WriteFile替代手动 open/write/close,简洁且自动 close -
json.MarshalIndent(data, "", " ")第二个参数是前缀(通常空),第三个是缩进符(推荐两个空格) - 如果数据含时间、自定义类型,需实现
json.Marshaler接口,否则会输出空对象或 panic
示例:
立即学习“go语言免费学习笔记(深入)”;
out, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
log.Fatal(err)
}
if err := os.WriteFile("output.json", out, 0644); err != nil {
log.Fatal(err)
}
注意 time.Time 和数字精度问题
Go 的 json 包默认把 time.Time 序列化为 RFC3339 字符串(如 "2024-05-20T14:30:00Z"),但如果原始 JSON 是时间戳数字(如 1716215400),直接解到 time.Time 会失败。同理,JSON 中的长整型 ID(如 "1234567890123456789")若用 int 接收,在 32 位系统或溢出时会截断。
实操建议:
- 时间字段统一用字符串接收(
string),再用time.Parse解析;或自定义类型实现UnmarshalJSON - 大整数 ID 改用
json.Number类型接收,再转int64或string,避免精度丢失 - 测试时用已知边界值验证(如 Unix 时间戳 0、超大整数),别只靠正常值覆盖
容易被忽略的是:json.Number 必须配合 UseNumber() 才生效,即在 json.Decoder 上显式调用,json.Unmarshal 不支持。









