Go 中嵌套结构体 JSON 序列化失败的解决方法

go 的 `json.marshal` 只能序列化导出(首字母大写)的结构体字段;未导出字段(小写开头)会被忽略,导致输出空对象 `{}`。

在 Go 语言中,JSON 序列化依赖于反射机制,而反射仅能访问导出(exported)字段——即字段名以大写字母开头的成员。你代码中的 Configitem 和 GuiConfig 所有字段均以小写字母开头(如 local_address、configs),因此 json.Marshal 无法读取它们的值,最终返回空 JSON 对象 {}。

✅ 正确做法是将所有需序列化的字段改为导出字段,并推荐添加 json 标签以控制键名和可选行为:

type Configitem struct {
    LocalAddress string `json:"local_address"`
    LocalPort    int    `json:"local_port"`
    Method       string `json:"method"`
    Password     string `json:"password"`
    Server       string `json:"server"`
    ServerPort   string `json:"server_port"`
    Timeout      int    `json:"timeout"`
}

type GuiConfig struct {
    Configs []*Configitem `json:"configs"`
    Index   int           `json:"index"`
}

修改后,原 main 函数无需改动,即可正确输出:

{"configs":[{"local_address":"eouoeu","local_port":111,"method":"eoeoue","password":"ouoeu","server":"oeuoeu","server_port":"qoeueo","timeout":3333}],"index":1}

⚠️ 注意事项:

  • 字段名首字母必须大写(如 LocalAddress),否则仍不可导出;
  • json 标签中的键名可保持小写(如 "local_address"),兼顾 Go 命名规范与 JSON 兼容性;
  • 若因封装需求必须保留字段私有性,可手动实现 json.Marshaler 接口,但会增加维护成本,一般不推荐;
  • 切勿依赖 unsafe 或反射绕过导出规则——这违背 Go 的设计哲学,且易引发兼容性问题。

总结:Go 的序列化安全模型建立在“导出即可见”原则之上。让结构体支持 JSON,第一步永远是——检查并修正字段的导出状态。