如何在 Go 中为同时包含导出与非导出字段的结构体实现自定义 JSON 编解码
发布时间 - 2026-01-11 00:00:00 点击率:次go 的 json 包默认忽略非导出(小写开头)字段,但可通过实现 marshaljson 和 unmarshaljson 方法,结合中间结构体,安全地序列化/反序列化混合可见性字段,避免递归调用栈溢出。
在 Go 中,JSON 编解码器仅能访问结构体的导出字段(即首字母大写的字段)。像 fieldA string 这样的非导出字段,默认不会参与 json.Marshal 或 json.Unmarshal。若需保留其 JSON 表现力,必须显式实现 json.Marshaler 和 json.Unmarshaler 接口——但关键在于:*绝不能在自定义方法中直接对 `Test调用json.Marshal/json.Unmarshal**,否则会触发无限递归(正如原问题中因嵌入*Test` 导致的栈溢出)。
推荐做法是定义一个纯导出、字段一一对应、仅用于 JSON 传输的中间结构体(如 TestJSON),它不包含任何业务逻辑,仅作为序列化桥梁:
type Test struct {
fieldA string // 非导出,需手动处理
FieldB int // 导出,可直接访问
FieldC string // 导出
}
// TestJSON:仅用于 JSON 编解码的导出结构体,字段名与 JSON key 对齐
type TestJSON struct {
FieldA string `json:"fieldA"`
FieldB int `json:"fieldB"`
FieldC string `json:"fieldC"`
}
func (t *Test) MarshalJSON() ([]byte, error) {
// 将当前 Test 实例的各字段显式赋值给 TestJSON,再序列化
return json.Marshal(TestJSON{
FieldA: t.fieldA,
FieldB: t.FieldB,
FieldC: t.FieldC,
})
}
func (t *Test) UnmarshalJSON(b []byte) error {
var temp TestJSON
if err := json.Unmarshal(b, &temp); err != nil {
return err
}
// 安全反向赋值:所有字段均为可写导出字段或本结构体内存可访问的非导出字段
t.fieldA = temp.FieldA
t.FieldB = temp.FieldB
t.FieldC = temp.FieldC
return nil
}✅ 优势说明:
- 无递归风险:TestJSON 是独立类型,与 Test 无嵌入或指针循环依赖;
-
可维护性强:新增字段时,只需同步更新 T
estJSON 定义及两个方法中的字段映射,IDE 可辅助检测遗漏; - 语义清晰:分离了数据模型(Test)与序列化契约(TestJSON),符合关注点分离原则。
⚠️ 注意事项:
- 若 Test 含嵌套结构体或切片,TestJSON 中对应字段也需保持相同导出性与 JSON tag;
- 不要尝试用 unsafe 或反射绕过导出限制——既破坏安全性,又丧失编译期检查;
- 若非导出字段本质是内部状态(如缓存、锁、连接句柄),则不应参与 JSON 序列化,此时应重新评估设计:是否真需暴露?能否用 json:"-" 显式忽略?或改用导出字段 + json tag 控制别名?
综上,使用专用中间结构体是 Go 中处理混合可见性字段 JSON 编解码的标准、安全且可扩展的方案。
# js
# json
# go
# 栈
# String
# 结构体
# 递归
# 循环
# 指针
# 接口
# 切片
# ide
# 序列化
# 编解码
# 见性
# 句柄
# 只需
# 均为
# 能在
# 自定义
# 不应
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
使用PHP下载CSS文件中的所有图片【几行代码即可实现】
Win11怎么恢复误删照片_Win11数据恢复工具使用【推荐】
敲碗10年!Mac系列传将迎来「触控与联网」双革新
C++时间戳转换成日期时间的步骤和示例代码
Laravel队列任务超时怎么办_Laravel Queue Timeout设置详解
Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】
Laravel如何实现本地化和多语言支持?(i18n教程)
如何在自有机房高效搭建专业网站?
在线教育网站制作平台,山西立德教育官网?
SQL查询语句优化的实用方法总结
Laravel如何与Vue.js集成_Laravel + Vue前后端分离项目搭建指南
浅析上传头像示例及其注意事项
如何为不同团队 ID 动态生成多个非值班状态按钮
JS弹性运动实现方法分析
Laravel广播系统如何实现实时通信_Laravel Reverb与WebSockets实战教程
Laravel如何使用Seeder填充数据_Laravel模型工厂Factory批量生成测试数据【方法】
Laravel怎么解决跨域问题_Laravel配置CORS跨域访问
如何快速搭建二级域名独立网站?
Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】
php485函数参数是什么意思_php485各参数详细说明【介绍】
微信小程序 require机制详解及实例代码
北京网站制作的公司有哪些,北京白云观官方网站?
HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】
如何在服务器上三步完成建站并提升流量?
Android自定义listview布局实现上拉加载下拉刷新功能
Claude怎样写约束型提示词_Claude约束提示词写法【教程】
制作电商网页,电商供应链怎么做?
Laravel如何使用Sanctum进行API认证?(SPA实战)
手机网站制作与建设方案,手机网站如何建设?
Laravel Eloquent关联是什么_Laravel模型一对一与一对多关系精讲
Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives
齐河建站公司:营销型网站建设与SEO优化双核驱动策略
如何选择可靠的免备案建站服务器?
javascript中的数组方法有哪些_如何利用数组方法简化数据处理
如何快速搭建个人网站并优化SEO?
HTML透明颜色代码在Angular里怎么设置_Angular透明颜色使用指南【详解】
软银砸40亿美元收购DigitalBridge 强化AI资料中心布局
网站图片在线制作软件,怎么在图片上做链接?
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)
Laravel如何处理文件下载请求?(Response示例)
三星、SK海力士获美批准:可向中国出口芯片制造设备
高性价比服务器租赁——企业级配置与24小时运维服务
Laravel如何使用查询构建器?(Query Builder高级用法)
如何快速搭建高效服务器建站系统?
Laravel如何实现多对多模型关联?(Eloquent教程)
Laravel如何实现API资源集合?(Resource Collection教程)
Laravel如何获取当前用户信息_Laravel Auth门面获取用户ID
如何在万网主机上快速搭建网站?
C++用Dijkstra(迪杰斯特拉)算法求最短路径
Laravel怎么实现模型属性的自动加密


estJSON 定义及两个方法中的字段映射,IDE 可辅助检测遗漏;