需传入结构体指针并确保字段导出,再用reflect.TypeOf获取类型、Field遍历字段、Tag.Get("json")提取标签值;小写字段或非指针传参会导致获取失败或panic。

怎么用 reflect 获取结构体字段的 json 标签值
直接通过 reflect.TypeOf 拿到结构体类型,再用 Field 方法遍历字段,调用 Tag.Get("json") 即可提取。注意:必须传入指针才能获取字段标签,否则 reflect.ValueOf 对非指针结构体返回的是副本,Field 会 panic。
- 字段必须是导出的(首字母大写),否则
reflect无法访问 -
Tag.Get("json")返回空字符串表示该字段没定义json标签,不是报错 - 如果标签形如
`json:"name,omitempty"`,Get("json")返回完整值"name,omitempty",需手动解析
type User struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
age int `json:"age"` // 小写字段,reflect 无法读取
}
v := reflect.ValueOf(&User{}).Elem()
t := v.Type()
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
jsonTag := field.Tag.Get("json")
if jsonTag != "" {
fmt.Println(field.Name, "->", jsonTag) // 输出:Name -> name,Email -> email,omitempty
}
}
为什么 reflect.StructTag.Get 有时返回空,但标签明明写了
常见原因不是语法写错,而是结构体字段未导出,或反射对象不是指针类型。另外,Tag 是字符串字面量,Go 不做语法校验,拼写错误(比如写成 `json:"name" yaml:"user"` 中多打了一个空格)会导致 Get("json") 返回空,但编译不报错。
- 检查字段名是否首字母大写;小写字段在反射中不可见
- 确认传入
reflect.TypeOf的是&Struct{}而非Struct{} - 用
fmt.Printf("%q", field.Tag)打印原始 tag 字符串,排查空格、全角符号、换行等隐形字符 -
json、db、validate等标签名区分大小写,Tag.Get("JSON")一定为空
如何安全解析 json 标签里的选项(如 omitempty、string)
标准库 encoding/json 自己实现了 structTag 解析逻辑,但未导出。实际项目中建议复用 json.StructTag —— 它是私有类型,不能直接 import;更稳妥的做法是手动切分,或使用社区轻量方案(如 github.com/mitchellh/reflectutil)。最简健壮方式是按逗号分割 + 去空格 + 判断前缀:
func parseJSONTag(tag string) (name string, opts map[string]bool) {
opts = make(map[string]bool)
if idx := strings.Index(tag, ","); idx == -1 {
name = tag
} else {
name = tag[:idx]
for _, opt := range strings.Split(tag[idx+1:], ",") {
opt = strings.TrimSpace(opt)
if opt != "" {
opts[opt] = true
}
}
}
return
}
// 使用:name, opts := parseJSONTag(`"user_id,omitempty,string"`)
// 得到 name="user_id", opts["omitempty"]=true, opts["string"]=true
在 ORM 或验证器里读取自定义标签(如 db:"user_name")要注意什么
自定义标签和 json 标签无本质区别,但要注意运行时性能和冲突风险。高频反射场景(如每请求解析一次结构体)应缓存 reflect.Type 和字段标签结果,避免重复遍历。
立即学习“go语言免费学习笔记(深入)”;
- 不要在每次 HTTP 请求中都调用
reflect.TypeOf+ 全字段扫描;提前构建字段映射表 - 多个库共用同一标签名(如都用
validate)可能语义冲突,建议加前缀(myapp_validate)或用独立 tag 键 - 若字段同时有
json和db标签,别假设它们值一致;显式分别读取,不复用解析结果 - 标签值含双引号(如
`db:"\"users\""`)是合法的,但手动解析时容易出错,优先用标准库已验证的解析逻辑(如复制encoding/json中的parseTag函数)










