如何在 Go 中递归遍历任意嵌套的 JSON 数据(无需预定义结构)

1次阅读

如何在 Go 中递归遍历任意嵌套的 JSON 数据(无需预定义结构)

本文介绍使用 `map[String]interface{}` 和递归类型断言,高效遍历动态、多层嵌套的 json 数据,自动识别并处理对象(map)、数组(slice)和基础值,适用于无法提前定义 Struct 的场景。

go 中处理未知结构的 jsON(即“任意嵌套 json”)时,最常用且推荐的方式是将 JSON 解码为 map[string]Interface{}(对应 JSON 对象)和 []interface{}(对应 JSON 数组)。由于 Go 是静态类型语言,interface{} 本身不携带运行时类型信息,因此必须通过类型断言(type assertion)类型开关(type switch 显式判断实际类型,才能安全访问其内容。

下面是一个完整、可直接运行的递归解析方案:

package main  import (     "encoding/json"     "fmt" )  func main() {     var m map[string]interface{}     if err := json.Unmarshal([]byte(input), &m); err != nil {         panic(err)     }     parseMap(m) }  // parseMap 递归遍历 JSON 对象(map[string]interface{}) func parseMap(m map[string]interface{}) {     for key, val := range m {         switch v := val.(type) {         case map[string]interface{}:             fmt.printf("→ Object: %sn", key)             parseMap(v) // 递归进入下一层对象         case []interface{}:             fmt.Printf("→ Array: %sn", key)             parseArray(v) // 递归进入数组元素         default:             // 基础类型:string, number (Float64), bool, nil             fmt.Printf("  %s: %v (type: %T)n", key, v, v)         }     } }  // parseArray 递归遍历 JSON 数组([]interface{}) func parseArray(a []interface{}) {     for i, val := range a {         switch v := val.(case) {         case map[string]interface{}:             fmt.Printf("  [Index %d] → Objectn", i)             parseMap(v)         case []interface{}:             fmt.Printf("  [Index %d] → Arrayn", i)             parseArray(v)         default:             fmt.Printf("  [Index %d]: %v (type: %T)n", i, v, v)         }     } }  const input = ` {   "outterJSON": {     "innerJSON1": {       "value1": 10,       "value2": 22,       "InnerInnerArray": ["test1", "test2"],       "InnerInnerJSONArray": [{"fld1": "val1"}, {"fld2": "val2"}]     },     "InnerJSON2": "NoneValue"   } }`

关键要点说明:

  • 类型安全是前提:interface{} 必须用 val.(type) 类型开关或 val.(map[string]interface{}) 断言明确转换,否则编译失败或 panic;
  • 递归终止条件自然存在:当遇到 string/float64/bool/nil 等非复合类型时,递归停止,直接输出;
  • 数组索引清晰可见:parseArray 显式打印 Index N,便于定位元素位置(例如 “fld1” 位于 InnerInnerJSONArray[0]);
  • 类型保留准确:fmt.Printf(“%T”, v) 可确认数字默认为 float64(JSON 规范无 int/float 区分),如需整数可做 int(v.(float64)) 转换(注意精度与边界检查);
  • 性能足够高效:无反射滥用,仅用原生类型判断,适合中等规模 JSON(GB 级建议改用 json.Decoder 流式解析)。

⚠️ 注意事项:

  • 若 JSON 中含 NULL,对应值为 nil(v == nil),需单独处理;
  • 不支持 JSON 中的 number 溢出或超长小数(Go float64 精度限制);
  • 如需提取所有 fld1 字段值,可在 parseMap 中增加匹配逻辑(例如 if key == “fld1” { fmt.Println(“Found fld1 =”, v) }),无需修改主干结构。

该方案是 Go 处理动态 JSON 的标准实践,简洁、健壮、易于扩展,特别适合配置解析、日志分析、API 响应泛化处理等场景。

text=ZqhQzanResources