Skip to content

Golang 结构体标签

前言

在 Golang 中,通过合理的使用结构体标签可以起到附加语言特性的相关处理,通过 json:",string" 可以在编码或解码时将数字转为字符串;通过 json:",omitempty" 当字段值为零值时可以在编码之后忽略该字段,在 json 数据中你压根就看到到该字段,它好像没有来过一样!

通用标签格式

go
type Example struct {
  FieldName Type `tag1:"value1" tag2:"value2" tag3:"value3,option1,option2"`
}

1. JSON 标签

基本用法

go
type User struct {
  ID       int    `json:"id"`               // 字段名为 "id"
  Name     string `json:"name"`             // 字段名为 "name"
  Password string `json:"-"`                // 忽略该字段
}

高级选项

go
type Product struct {
  ID          int      `json:"id"`
  Name        string   `json:"name,omitempty"`      // 空值时忽略
  Price       float64  `json:"price,string"`        // 数字转为字符串
  Tags        []string `json:"tags,omitempty"`      // 空切片时忽略
  CreatedAt   time.Time `json:"created_at"`
  IsAvailable bool     `json:"is_available"`

  // 复杂选项组合
  Score       float64  `json:"score,omitempty,string"` // 多个选项
}

选项说明:

  • omitempty - 零值时忽略该字段
  • string - 将数字/布尔值编码为字符串
  • - - 完全忽略该字段

2. MapStructure 标签

基本用法(用于 Viper 等配置解析)

go
type Config struct {
  ServerHost string `mapstructure:"server_host"`    // 映射下划线命名
  ServerPort int    `mapstructure:"server_port"`
}

嵌入结构体处理

go
type BaseConfig struct {
  Name string `mapstructure:"name"`
  Env  string `mapstructure:"env"`
}

type ServiceConfig struct {
  BaseConfig `mapstructure:",squash"`  // 关键:展平嵌入结构体
  Timeout    time.Duration `mapstructure:"timeout"`
}

特殊选项:

  • ,squash - 展平嵌入结构体的字段
  • ,remain - 收集未映射的字段到 map
  • - - 忽略字段

3. YAML 标签

基本用法

go
type Config struct {
  Host     string   `yaml:"host"`
  Port     int      `yaml:"port,omitempty"`
  Features []string `yaml:"features,flow"`  // 内联数组格式
}

流式风格选项

go
type Deployment struct {
  Replicas int      `yaml:"replicas"`
  Images   []string `yaml:"images,flow"`    // 输出为: images: [a, b, c]
}

4. 数据库相关标签

GORM 标签

go
type User struct {
  gorm.Model
  Name     string `gorm:"type:varchar(100);not null;uniqueIndex"`
  Email    string `gorm:"type:varchar(255);unique;index:idx_email"`
  Age      int    `gorm:"default:18;check:age > 0"`
  Status   string `gorm:"type:enum('active','inactive');default:'active'"`
}

XORM 标签

go
type Product struct {
  ID       int64  `xorm:"pk autoincr 'product_id'"`
  Name     string `xorm:"varchar(100) notnull index"`
  Price    float64 `xorm:"decimal(10,2) default 0.00"`
  IsActive bool   `xorm:"default true"`
}

5. 验证标签

validator.v9/v10

go
type User struct {
  ID       int    `validate:"required,gt=0"`
  Name     string `validate:"required,min=2,max=50"`
  Email    string `validate:"required,email"`
  Age      int    `validate:"gte=0,lte=150"`
  Password string `validate:"required,min=8"`
  Website  string `validate:"url"`
  IP       string `validate:"ip"`
}

Gin 绑定验证

go
type LoginRequest struct {
  Username string `json:"username" binding:"required,alphanum,min=3,max=20"`
  Password string `json:"password" binding:"required,min=8"`
  Email    string `json:"email" binding:"omitempty,email"`
}

6. XML 标签

go
type Person struct {
  XMLName   xml.Name `xml:"person"`
  ID        int      `xml:"id,attr"`           // 作为属性
  FirstName string   `xml:"name>first"`        // 嵌套元素
  LastName  string   `xml:"name>last"`
  Age       int      `xml:"age"`
  Bio       string   `xml:",chardata"`         // 字符数据
  Comment   string   `xml:",comment"`          // 注释
}

7. 表单标签(用于 HTTP 表单)

go
type LoginForm struct {
  Username string `form:"username" binding:"required"`
  Password string `form:"password" binding:"required"`
  Remember bool   `form:"remember_me"`
}

8. 环境变量标签

envconfig

go
type Config struct {
  DatabaseURL string `envconfig:"DATABASE_URL" required:"true"`
  Port        int    `envconfig:"PORT" default:"8080"`
  Debug       bool   `envconfig:"DEBUG" default:"false"`
}

9. 协议缓冲区标签

go
type User struct {
  ID       int64  `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
  Name     string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
  Email    string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"`
}

10. 自定义标签

自定义解析

go
type Config struct {
  Host     string `custom:"host;required;default=localhost"`
  Port     int    `custom:"port;min=1;max=65535"`
  Timeout  time.Duration `custom:"timeout;unit=second"`
}

// 自定义解析函数
func ParseCustomTag(tag string) map[string]string {
  // 解析逻辑
}

综合示例

go
type AppConfig struct {
  // JSON 序列化
  Name string `json:"name" yaml:"name" mapstructure:"name"`
  // 数据库映射
  DatabaseURL string `json:"database_url" mapstructure:"database_url" envconfig:"DATABASE_URL"`
  // 验证规则
  Port int `json:"port" mapstructure:"port" validate:"required,gt=0,lte=65535"`
  // 忽略字段
  SecretKey string `json:"-" mapstructure:"secret_key" yaml:"-"`
  // 时间格式
  CreatedAt time.Time `json:"created_at" mapstructure:"created_at" time_format:"2006-01-02"`
  // 嵌入结构体
  BaseConfig `mapstructure:",squash" json:",inline" yaml:",inline"`
}

type BaseConfig struct {
  Environment string `json:"environment" mapstructure:"environment"`
  Version     string `json:"version" mapstructure:"version"`
}

最佳实践

  1. 一致性:在整个项目中保持标签命名的一致性
  2. 明确性:使用明确的字段名映射,避免歧义
  3. 安全性:敏感字段使用 json:"-" 避免序列化
  4. 验证:结合验证标签确保数据完整性
  5. 文档:为复杂的标签组合添加注释说明

常见问题解决

Viper 嵌入结构体问题

go
// 错误:嵌入结构体字段无法映射
type ServiceConfig struct {
  ServiceConfig
  Timeout time.Duration
}

// 正确:使用 squash
type ServiceConfig struct {
  ServiceConfig `mapstructure:",squash"`
  Timeout time.Duration `mapstructure:"timeout"`
}

空值处理

go
// 避免输出空值字段
type Config struct {
  OptionalField string `json:"optional_field,omitempty"`
  EmptyArray    []string `json:"empty_array,omitempty"`
}

这样就能全面掌握 Go 结构体标签的各种用法了!