Go结构体字段必须首字母大写才能被外部包(如encoding/json、GORM)访问和序列化;小写字段无论加何种标签均被忽略,这是反射机制依赖的导出规则。

Go 里没有“设置自定义字段”这个动作——字段是结构体定义时就固定的,不能运行时增删。你真正想做的,通常是这三件事之一:给结构体字段加 JSON/BSON 序列化别名、让字段参与数据库读写、或控制字段是否导出(首字母大小写)。下面分场景说清楚。
json:"xxx" 标签写错导致字段不出现
常见现象:结构体字段值明明有,json.Marshal 输出却是 {} 或某个字段消失。
- 检查字段是否导出:必须首字母大写,
Name string✅,name string❌(后者无论加什么 tag 都进不了 JSON) - 检查 tag 语法:正确是
`json:"user_id"`,不是`json:"user_id,"`(多逗号会静默失效,退回到默认小写驼峰) -
omitempty不等于“空时不传”,它对零值敏感:*string为nil时消失,但""(空字符串)仍会输出"user_id": "" - 嵌套结构体也要逐层检查导出性:如果
Profile ProfileInfo没生效,大概率是ProfileInfo里的字段没大写
数据库字段名和 Go 字段名不一致
比如数据库列是 created_at,但你想在结构体里叫 CreatedAt,又不想手动映射。
- 用
db:"created_at"标签(GORM)或column:"created_at"(SQLX),具体取决于 ORM - 标准库
database/sql不认这些标签,得靠Scan时按顺序赋值,或用map[string]interface{}中转 - 如果字段类型是自定义的(比如
type Email string),必须同时实现driver.Valuer和sql.Scanner,缺一不可,否则Scan或Exec直接 panic
想让某个字段完全不参与序列化
不是设成零值,而是压根不出现在 JSON 或数据库 INSERT 语句里。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
立即学习“go语言免费学习笔记(深入)”;
- JSON 场景:用
`json:"-"`,注意是短横线,不是空字符串 - BSON 场景:
`bson:"-"`同理 - 数据库场景:GORM 用
`gorm:"-"`;SQLX 没内置支持,得靠struct{}匿名嵌入或显式 SELECT 列表避开 - 别用
json:"foo,omitempty"代替json:"-":前者在值非零时仍会出现,后者永远不出现
字段名冲突或结构不确定时用 json.RawMessage
比如 API 返回的 data 字段有时是对象,有时是数组,或者你暂时不想解析它。
- 声明字段为
Data json.RawMessage,它会原样保存原始字节,跳过所有字段名转换和类型校验 - 后续要用时再调用
json.Unmarshal(Data, &target),此时才真正触发解析 - 它不关心 key 是
user_id还是userId,因为还没开始解析——适合做兼容层或延迟处理 - 注意:
json.RawMessage是[]byte别名,不能直接打印或比较,得先解码
最容易被忽略的是导出规则:Go 的反射、JSON、GORM、SQLX 全部依赖首字母大写判断“是否可见”。哪怕你把 tag 写得再完美,字段小写了就等于不存在。这不是 bug,是设计前提。

















