go结构体字段必须首字母大写(导出)才能被json.marshal序列化,小写私有字段即使加json:"xxx"标签也会被忽略,导致输出空对象{}或字段缺失。

结构体字段必须导出才能被 json.Marshal 序列化
Go 的 json 包无法访问小写字母开头的私有字段,哪怕你加了 json:"xxx" 标签也没用。常见错误是定义了 name string 这样的字段,结果序列化出来是空对象 {} 或缺失字段。
正确做法是确保所有要参与 JSON 转换的字段名首字母大写:
-
Name string `json:"name"`✅ -
Children []Node `json:"children"`✅ -
children []Node❌(完全被忽略)
递归结构体必须用指针避免无限嵌套 panic
如果直接在结构体中嵌套自身类型(如 Children []Node),json.Marshal 在反射遍历时可能因深度过深或循环引用触发栈溢出或 panic。尤其当子节点意外指向父节点时,问题更隐蔽。
安全写法是使用指针切片,并在构造时确保无环:
-
Children []*Node `json:"children"`—— 推荐,明确语义且避免值拷贝爆炸 - 初始化时检查是否重复添加同一地址的节点
- 测试时可用
json.MarshalIndent加缩进输出,快速观察嵌套层级是否失控
omitempty 标签对空切片和 nil 切片行为不同
递归结构中常遇到「叶子节点 children 字段该不该出现」的问题。注意:[]Node{}(空切片)和 nil 在加 omitempty 后表现一致(都不输出),但它们在 Go 语义上不同,会影响后续逻辑判断。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
建议统一初始化为 nil,并在业务层用 len(n.Children) == 0 判断是否为叶子节点:
Children []*Node `json:"children,omitempty"`- 创建新节点时不要写
Children: []*Node{},直接留空或显式赋nil - 反序列化时,
json.Unmarshal对缺失字段默认设为nil,与预期一致
jstree 兼容结构需严格匹配 data 和 children 键名
前端用 jstree 时,它默认读取节点的 data(文本)和 children(子节点数组)字段。如果你的结构体字段名是 Name,就必须通过 tag 映射过去,否则前端收不到内容。
典型定义示例:
type Node struct {
Name string `json:"data"`
Children []*Node `json:"children"`
}
注意点:
-
data不是字符串字面量,而是 jstree 的约定键名,不能写成json:"name" - 若需额外字段(如 id、state),可加字段并打对应 tag,jstree 会忽略不认识的键
- 空
Children设为nil后,序列化结果里不出现"children": [],jstree 仍能正确识别为无子节点










