json.marshalindent用于生成带缩进的可读json,需传入原生数据结构及正确prefix(如"")和indent(如" ")参数,不可传已序列化字符串,且中文不转义需改用json.encoder配合setescapehtml(false)。

用 json.MarshalIndent 生成带缩进的 JSON 字符串
直接调用 json.Marshal 得到的是紧凑格式(无换行、无空格),要美化输出必须用 json.MarshalIndent。它比 Marshal 多两个参数:缩进前缀(如 "")和每个层级的缩进符(如 " " 或 "\t")。
常见错误是传错参数顺序,比如把缩进符当成了前缀,结果 JSON 每行开头多出一堆空格但没换行;或者传了空字符串当缩进符,导致输出和 Marshal 一样。
-
json.MarshalIndent(data, "", " ")是最常用组合:不加全局前缀,每层缩进两个空格 - 如果结构体字段含非导出字段(小写开头),它们不会被序列化,且不报错——这是 Go 的默认行为,不是 bug
- 若需控制某个字段是否出现,用 struct tag:
json:"name,omitempty"可跳过零值字段
处理时间、浮点数等类型时的格式陷阱
Go 的 json 包对某些类型有默认编码规则,容易和预期不符。比如 time.Time 默认转成 RFC3339 字符串(含时区),float64 可能输出 123.0 而不是 123,影响可读性。
不需要自定义 marshaler 时,优先用字段 tag 控制输出:
- 时间字段加
json:"created_at,string"→ 输出带引号的字符串,如"2024-05-20T10:30:00Z" - 整数型 float 字段加
json:"score,string"→ 强制转字符串再序列化,避免小数点 - 忽略空字段统一加
omitempty,但注意指针或接口零值也会被跳过
数组元素过多时,要不要手动分块或限深?
json.MarshalIndent 本身不做截断或限深,它忠实地递归整个结构。如果结构体数组里嵌套了几十层 map 或超长 slice,输出会很大,但不会 panic 或卡死。
真正的问题是调试查看时眼花缭乱,或日志系统因单行超长被截断。这时不是改 JSON 库,而是加一层控制:
- 用
fmt.Printf("%%+v", data)查看 Go 原生结构(适合调试,非 JSON) - 对大数组,先取前 5 个元素:
data[:min(len(data), 5)]再 MarshalIndent - 不要在生产日志中无条件打印完整美化 JSON,尤其含敏感字段时——先脱敏再格式化
为什么 json.Indent 要求输入已是合法 JSON 字节?
这个函数不是用来美化 Go 结构体的,而是对已有的 JSON 字符串(比如从 API 读回来的 []byte)做重新缩进。它不解析 Go 类型,只做语法树级别的格式重排。
误用场景:有人先 json.Marshal 得到紧凑 JSON,再喂给 json.Indent,看似可行,但多了一次无意义的反序列化/重序列化开销,还可能因浮点精度或 time 格式差异导致内容微变。
- 正确链路:结构体 →
json.MarshalIndent(一步到位) - 仅当已有 JSON 字节且无法修改源头时,才用
json.Indent(dst, src, "", " ") - 注意
dst必须是预先分配好的[]byte,否则 panic
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











