如何在 Go 中解析包含多个键值对对象的 JSON 数组并合并为单一 map

本文介绍如何将形如 `[{"key1":"val1"},{"key2":"val2"}]` 的 json 数组解析为一个统一的 `map[string]string`,涵盖解码流程、类型选择、遍历合并技巧及常见注意事项。

在 Go 中处理 JSON 数据时,若原始数据是以多个独立对象组成的数组形式存在(例如 [{"C

at":"small animal"},{"Cow":"Big animal"}]),而非单个扁平对象(如 {"Cat":"small animal","Cow":"Big animal"}),则不能直接 json.Unmarshal 到 map[string]string——因为 JSON 格式不匹配:前者是 JSON 数组([]),后者是 JSON 对象({})。

正确的做法是分两步解析

  1. 先将 JSON 解码为 []map[string]string(即字符串映射的切片);
  2. 再遍历该切片,逐个提取每个子 map 的键值对,并合并到一个新的 map[string]string 中。

以下是完整可运行示例:

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

func main() {
    // 原始 JSON 必须是数组格式:用方括号 [] 包裹多个对象
    jsonText := []byte(`[
        {"Cat": "small animal"},
        {"Cow": "Big animal"},
        {"Dog": "loyal pet"}
    ]`)

    var rawList []map[string]string
    if err := json.Unmarshal(jsonText, &rawList); err != nil {
        log.Fatal("JSON 解析失败:", err)
    }

    // 合并为单个 map
    resultMap := make(map[string]string)
    for _, item := range rawList {
        for key, value := range item {
            resultMap[key] = value // 若存在重复 key,后出现的值会覆盖前者
        }
    }

    fmt.Printf("合并后的字典: %+v\n", resultMap)
    // 输出: 合并后的字典: map[Cat:small animal Cow:Big animal Dog:loyal pet]
}

关键说明

  • 输入 JSON 必须是合法数组(以 [ 开头、] 结尾),否则 json.Unmarshal 会报错 invalid character ... expecting [。
  • 使用 []map[string]string 是最直观且安全的中间类型——它明确表达了“多个无序键值对对象的集合”。
  • 若原始数据实际是 {...} 包裹(即顶层为对象而非数组),需先确认其结构是否为「带字段名的包装对象」(如 {"data": [...]}),此时应定义结构体解析,而非强行转为 []map。
  • 合并逻辑中未做 key 冲突校验;如业务要求检测重复键,可在内层循环添加 if _, exists := resultMap[key]; exists { /* 处理冲突 */ }。

? 进阶建议

  • 对于大规模数据,可考虑使用 json.Decoder 流式解析避免内存峰值;
  • 若键类型不固定(如含数字或空格),建议统一用 map[string]interface{} + 类型断言,再转换为目标类型;
  • 生产环境推荐配合 json.RawMessage 或自定义 UnmarshalJSON 方法提升健壮性与可维护性。

通过该模式,你可灵活应对各类“分散式键值对集合”的 JSON 场景,兼顾简洁性与可扩展性。