json.MarshalIndent 用于生成带缩进的可读JSON,需传入空字符串前缀和缩进符(如" "),返回[]byte需转string,错误不可忽略;注意字段导出、time.Time处理及nil指针编码行为。

用 json.MarshalIndent 实现带缩进的 JSON 输出
Go 标准库的 json.Marshal 默认输出无空格紧凑格式,不适合调试或日志查看。真正“美化”的关键在 json.MarshalIndent ——它接受前缀和缩进字符串,生成可读性强的结构化输出。
实操建议:
- 第二个参数是前缀(通常传空字符串
""),第三个是缩进符(常用" "或"\t") - 如果数据含非 JSON 可序列化字段(如函数、未导出字段、
map[interface{}]interface{}中的非字符串 key),会直接报错json: unsupported type: xxx - 注意返回值是
[]byte,别忘了用string()转成字符串;错误不可忽略,否则可能得到空字符串却无提示
data := map[string]interface{}{"name": "Alice", "scores": []int{95, 87}}
b, err := json.MarshalIndent(data, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b)) // 美化后输出
处理 time.Time、nil 指针等常见类型问题
默认 JSON 编码对 time.Time 输出为 RFC3339 字符串(如 "2024-05-22T14:30:00Z"),看起来正常,但如果你自定义了 Time 字段并重写了 MarshalJSON,可能意外触发 panic;而 nil 指针字段会被编码为 null,这本身合法,但容易被误认为数据缺失。
实操建议:
- 确认结构体字段是否都已导出(首字母大写),否则
json包完全忽略它们 - 含
time.Time的结构体,建议统一嵌入json:",string"tag 来强制转为字符串,避免时区/精度混淆 - 若需把
nil *T显示为{}而非null,得自己实现MarshalJSON方法,不能依赖默认行为
封装成通用函数时必须处理错误与字节转换
很多人写 func Pretty(v interface{}) string,直接 return string(json.MarshalIndent(...)),结果遇到错误时返回空字符串,调用方毫无察觉。这不是“美化”,是埋雷。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
实操建议:
- 不要隐藏错误:函数签名应为
func Pretty(v interface{}) (string, error) - 避免反复分配:不建议每次调用都新建
bytes.Buffer或做多余string()转换;json.MarshalIndent返回[]byte已足够,调用方按需转 - 如果只是用于日志,可加一层
log.Printf("data: %s", PrettyOrPanic(v))辅助函数,但生产代码中仍应显式检查错误
为什么不用第三方库(如 gojay 或 easyjson)?
它们主打高性能序列化,但美化输出不是核心场景;gojay 不支持 MarshalIndent 风格的格式化,easyjson 生成的代码默认也不带缩进。标准库的 json.MarshalIndent 在可读性、兼容性和维护成本上仍是首选。
唯一要注意的是性能敏感场景:如果高频调用且数据巨大,MarshalIndent 比 Marshal 多一次内存遍历,但日常调试、配置打印、API 响应预览完全无压力。
真正容易被忽略的点是:美化 ≠ 正确。你看到缩进整齐的 JSON,不代表里面没 NaN、+Inf 或循环引用——这些在 MarshalIndent 前就会失败。先确保能序列化,再谈好不好看。

















