JSON标签是结构体字段的元信息,由encoding/json包通过反射读取;手动解析需用reflect获取tag值并按“name,option”格式拆分处理,注意导出字段限制和常见选项语义。
Go 语言中,json 标签本身不参与运行时逻辑,它只是结构体字段的元信息;真正读取和利用这些标签的是 encoding/json 包内部的反射逻辑。要手动解析 JSON 标签(比如做自定义序列化、字段校验、API 文档生成等),你需要用 reflect 包提取结构体字段的 json 标签值,并按规则解析其内容。
通过 reflect.TypeOf 获取结构体类型,再遍历每个字段,调用 Field(i).Tag.Get("json") 即可拿到原始标签字符串。注意:必须使用导出字段(首字母大写),非导出字段无法被反射访问。
例如:
type User struct {
ID int `json:"id"`
Name string `json:"name,omitempty"`
Email string `json:"email"`
Secret string `json:"-"`
}
t := reflect.TypeOf(User{})
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
tag := field.Tag.Get("json") // 返回 "id"、"name,omitempty"、"email"、"-"
fmt.Println(field.Name, "->", tag)
}
JSON 标签格式为 "name,option1,option2",其中:
omitempty 表示零值字段不输出- 表示该字段完全忽略(跳过编解码)string)由 json 包解释,反射层不处理你可以手动拆分并判断:
func parseJSONTag(tag string) (name string, omitEmpty bool, ignored bool) {
if tag == "-" {
return "", false, true
}
parts := strings.Split(tag, ",")
name = parts[0]
if name == "" {
name = "default_name" // 实际中可用 field.Name 替代
}
for _, opt := range parts[1:] {
if opt == "omitempty" {
omitEmpty = true
}
}
return
}
若你有一个 JSON 键名(如 "user_name"),想找到对应结构体字段,需遍历所有字段,解析其 json 标签,比对名称:
- 字段注意:标准 json.Unmarshal 的字段匹配逻辑更复杂(支持大小写不敏感、嵌套别名等),但自定义场景下只需基础映射即可。
Tag.Get("json") 返回空字符串不代表没标签,可能是 json:"",需额外判断strings.TrimSpace
reflect.Kind() 判断是否为 struct基本上就这些。掌握 reflect.StructTag 和手动解析逻辑,就能灵活支撑序列化增强、ORM 映射、OpenAPI 生成等场景。不需要魔改标准库,靠几行反射 + 字符串处理就能复刻核心行为。