
本文介绍使用 `map[string]interface{}` 和类型断言递归解析动态 json 的标准方法,通过 `type switch` 区分对象、数组与基础值,实现对任意深度嵌套结构(如二级对象、嵌套数组及其中的 json 对象)的完整遍历与键值提取。
在 Go 中处理未知结构的 JSON(即“动态 JSON”)时,无法预先定义 struct,此时应使用 map[string]interface{} 作为通用解码目标。但该类型本质是 interface{} 的嵌套组合,需借助类型断言(Type Assertion) 和 类型开关(Type Switch) 显式识别内部数据类型(如 map[string]interface{}、[]interface{} 或基本类型),才能安全地递归遍历。
以下是一个健壮、可扩展的递归遍历方案,支持无限嵌套层级:
package main
import (
"encoding/json"
"fmt"
)
func main() {
var data map[string]interface{}
if err := json.Unmarshal([]byte(input), &data); err != nil {
panic(err)
}
parseMap(data, 0) // 传入缩进层级,便于阅读输出
}
// parseMap 递归解析 JSON 对象(map[string]interface{})
func parseMap(m map[string]interface{}, indent int) {
for key, val := range m {
indentStr := getIndent(indent)
switch v := val.(type) {
case map[string]interface{}:
fmt.Printf("%s? %s (object)\n", indentStr, key)
parseMap(v, indent+1)
case []interface{}:
fmt.Printf("%s? %s (array)\n", indentStr, key)
parseArray(v, indent+1)
default:
// 将任意基础值(string/number/bool/nil)统一转为字符串表示
fmt.Printf("%s✅ %s: %v\n", indentStr, key, v)
}
}
}
// parseArray 递归解析 JSON 数组([]interface{})
func parseArray(arr []interface{}, indent int) {
for i, item := range arr {
indentStr := getIndent(indent)
switch v := item.(type) {
case map[string]interface{}:
fmt.Printf("%s? Index %d (object)\n", indentStr, i)
parseMap(v, indent+1)
case []interface{}:
fmt.Printf("%s? Index %d (array)\n", indentStr, i)
parseArray(v, indent+1)
default:
fmt.Printf("%s✅ Index %d: %v\n", indentStr, i, v)
}
}
}
// 辅助函数:生成缩进字符串,提升输出可读性
func getIndent(level int) string {
return fmt.Sprintf("%*s", level*2, "")
}
const input = `
{
"outterJSON": {
"innerJSON1": {
"value1": 10,
"value2": 22,
"InnerInnerArray": ["test1", "test2"],
"InnerInnerJSONArray": [{"fld1": "val1"}, {"fld2": "val2"}]
},
"InnerJSON2": "NoneValue"
}
}`关键要点说明:
- ✅ 类型安全:使用 switch v := val.(type) 避免运行时 panic,清晰区分 map、slice 和基础值;
- ✅ 完全递归:parseMap 处理对象,parseArray 处理数组,二者相互调用,支持任意嵌套深度;
- ✅ 键值统一处理:所有叶子节点(如 "fld1": "val1"、"value1": 10)均以 key: value 形式输出,便于后续字符串处理;
- ✅ 可扩展性强:若需提取特定字段(如所有 fld1 的值),可在 default 分支中添加条件判断逻辑;
- ⚠️ 注意事项:
- json.Unmarshal 对 nil、null 解析为 nil(interface{} 类型),需额外判断避免空指针;
- 若 JSON 含 float64(JSON 数字默认类型),需显式转换为 int 或 string;
- 生产环境建议封装为可配置的遍历器(如支持跳过某些 key、自定义回调函数等)。
此方法是 Go 官方推荐的「解码任意数据」范式(见 JSON and Go),兼顾简洁性、可读性与工程可靠性,特别适合配置解析、API 响应泛化处理等场景。










