Go 中嵌套数据结构的 JSON 序列化:从 Python 类比入门

本文详解如何在 go 中构建与 python 字典等效的嵌套数据结构(如含切片的 map),并正确序列化为 json,重点解决 `properties` 字段需为对象数组而非单个对象的常见误区。

在 Python 中,{'Properties': [{'key': 'data1', 'value': 'data2'}]} 这样的结构天然支持动态嵌套,因为字典和列表可任意组合。但在 Go 中,类型系统要求显式声明结构——尤其是当某个字段应为「对象数组」(即 JSON 中的 []object)时,必须使用切片(slice)包裹映射(map),而非直接使用 map[string]string。

关键区别在于:

  • ✅ []map[string]string → 对应 JSON 的 [{"key":"data1","value":"data2"}](数组,含一个对象)
  • ❌ map[string]string → 对应 JSON 的 {"key":"data1","value":"data2"}(单个对象,无方括号)

以下是完整、可运行的 Go 示例:

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    data := map[string]interface{}{
        "Locations":  []string{},
        "Dates":      []string{},
        "Properties": []map[string]string{
            {"key": "data1", "value": "data2"},
        },
        "Category": "all",
        "Offset":   "0", // 注意:原 Python 示例未含此字段,此处按用户尝试代码保留
    }

    dataJSON, err := json.Marshal(data)
    if err != nil {
        panic(err)
    }

    fmt.Println(string(dataJSON))
    // 输出: {"Category":"all","Dates":[],"Locations":[],"Offset":"0","Properties":[{"key":"data1","value":"data2"}]}
}

? 注意事项

  • json.Marshal 默认按字典序排列键名(如 "Category" 在 "Dates" 前),若需严格保序,应改用结构体(struct)配合 json 标签,而非 map[string]interface{};
  • []map[string]string 是最简方案,但缺乏类型安全;生产环境推荐定义明确结构体,例如:
type Property struct {
    Key   string `json:"key"`
    Value string `json:"value"`
}
type Data struct {
    Locations  []string  `json:"Locations"`
    Dates      []string  `json:"Dates"`
    Properties []Property `json:"Properties"`
    Category   string    `json:"Category"`
    Offset     string    `json:"Offset"`
}

这样既提升可读性与编译期检查能力,又完全兼容 JSON 序列化。总之,Go 的「显式即安全」哲学虽需初期适应,却能有效规避运行时类型错误——掌握 []map 与 struct 的选用场景,是写出健壮 JSON 处理逻辑的关键一步。