Go 语言通过 reflect 包解析 struct tag 提取元信息,需遵循 key:"value" 格式规则并用 Tag.Get 或 Tag.Lookup 安全提取;错误写法如单引号、多余空格或重复 key 会导致解析失效。

Go 语言的反射(reflect)包支持通过结构体字段的 struct tag 提取元信息,常用于序列化(如 JSON、XML)、校验、ORM 映射等场景。关键在于正确书写 tag 字符串,并用 reflect.StructTag.Get 或 reflect.StructField.Tag.Lookup 安全提取值。
struct tag 的基本格式规则
每个字段的 tag 是一个反引号包裹的字符串,由多个 key:"value" 对组成,用空格分隔:
- key 必须是纯 ASCII 字母或下划线,不能含空格、冒号、引号或 Unicode 字符
- value 必须用双引号包裹(不能用单引号或反引号),内部可使用转义(如
"a\"b") - 同一个 key 出现多次时,以最后一个为准(Go 不报错但会覆盖)
- 不合法的 tag(如缺少引号、引号不匹配)会导致编译通过但运行时
Tag.Get返回空字符串
安全提取 tag 值的两种推荐方式
不要直接操作 tag 字符串。应使用标准库提供的解析方法:
-
field.Tag.Get("json"):返回对应 key 的 value,未找到则返回空字符串 -
field.Tag.Lookup("json"):返回(value string, ok bool),更明确地区分“不存在”和“值为空” - 避免手动
strings.Split或正则解析 —— tag 内部可能含空格或转义,标准解析器已处理所有边界情况
常见实战误区与修复示例
以下写法看似合理,实则无效或危险:
立即学习“go语言免费学习笔记(深入)”;
-
json:"name,omitempty" db:"user_name"✅ 正确:两个独立 key,空格分隔 -
json:"name, omitempty"❌ 错误:逗号后多空格,JSON 解析器会把整个值当字段名(如"name, omitempty"),而非启用 omitempty -
json:'name'❌ 错误:用了单引号,编译不报错但Get("json")返回空 -
json:"name,omitempty" json:"id"⚠️ 警告:后一个覆盖前一个,最终只生效json:"id"
完整可运行示例:解析 JSON 和自定义 tag
下面代码演示如何获取并判断字段是否被标记为忽略(omitempty)、是否有别名、以及是否存在自定义验证 tag:
type User struct {
ID int `json:"id"`
Name string `json:"name,omitempty" validate:"required,min=2"`
Age int `json:"age" validate:"gte=0,lte=150"`
}
func inspectTags() {
t := reflect.TypeOf(User{})
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
fmt.Printf("字段: %s\n", f.Name)
if jsonTag, ok := f.Tag.Lookup("json"); ok {
fmt.Printf(" JSON tag: %q\n", jsonTag) // 如 "id", "name,omitempty"
if strings.Contains(jsonTag, "omitempty") {
fmt.Println(" → 启用 omitempty")
}
}
if vTag, ok := f.Tag.Lookup("validate"); ok {
fmt.Printf(" Validate tag: %q\n", vTag)
}
}
}
基本上就这些。tag 规则不复杂但容易忽略细节,坚持用 Lookup 判空、严格按格式书写,就能稳定支撑各类元编程需求。










