Appearance
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"`
}
最佳实践
- 一致性:在整个项目中保持标签命名的一致性
- 明确性:使用明确的字段名映射,避免歧义
- 安全性:敏感字段使用
json:"-"
避免序列化 - 验证:结合验证标签确保数据完整性
- 文档:为复杂的标签组合添加注释说明
常见问题解决
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 结构体标签的各种用法了!