
Go语言中,若嵌入结构体的字段未导出(首字母小写),json.Marshal 会忽略所有字段,导致输出空对象 {};解决方法是将字段名首字母大写以满足导出规则,并避免与同名方法冲突。
go语言中,若嵌入结构体的字段未导出(首字母小写),`json.marshal` 会忽略所有字段,导致输出空对象 `{}`;解决方法是将字段名首字母大写以满足导出规则,并避免与同名方法冲突。
在 Go 中,encoding/json 包仅能序列化导出字段(即首字母大写的字段)。当使用结构体嵌入(embedding)时,这一规则依然严格适用——即使嵌入的结构体本身定义完整,若其内部字段未导出,它们在 JSON 序列化过程中仍会被完全忽略。
例如,以下代码会导致 json.Marshal 输出空对象 {}:
type Parent struct {
name string // 首字母小写 → 未导出 → 被忽略
value int // 同样未导出
}
type Child struct {
Parent // 嵌入
}调用 json.Marshal(Child{}) 的结果为:{}。
✅ 正确做法是将嵌入结构体中的字段改为导出字段,并确保不与方法名冲突(如原示例中存在 Name() 和 Value() 方法,则字段不可再命名为 Name/Value,否则引发编译错误):
立即学习“go语言免费学习笔记(深入)”;
type Parent struct {
Name string `json:"name"` // 导出字段 + 可选 tag
Value int `json:"value"`
}
type Child struct {
Parent
}此时 json.Marshal(Child{Parent: Parent{Name: "test", Value: 42}}) 将输出:
{"name":"test","value":42}
⚠️ 注意事项:
- 嵌入结构体的字段必须导出,否则无论是否嵌入,均无法参与 JSON 编解码;
- 若嵌入结构体含同名方法(如 Name()),字段名需重命名(如改为 NameVal),避免标识符冲突;
- 可通过 json tag 显式控制字段名、忽略空值(omitempty)等行为,提升序列化灵活性;
- 使用 json.MarshalIndent 可生成格式化输出,便于调试。
总结:Go 的 JSON 序列化遵循严格的导出规则,嵌入不是“魔法穿透”机制——它简化的是方法继承与字段访问语法,而非绕过可见性约束。始终确保待序列化的字段可导出,是编写健壮 JSON 接口的基础前提。










