结构体标签 #

一、标签概述 #

结构体标签是为字段添加的元数据,通过反射读取。

二、标签语法 #

2.1 基本语法 #

go
type User struct {
    Name string `tag1:"value1" tag2:"value2"`
}

2.2 多标签 #

go
type User struct {
    Name string `json:"name" xml:"name" db:"user_name"`
}

2.3 标签格式 #

  • 键值对形式:key:"value"
  • 多个标签用空格分隔
  • 值可以用逗号分隔多个选项

三、JSON标签 #

3.1 基本用法 #

go
type User struct {
    Name  string `json:"name"`
    Age   int    `json:"age"`
    Email string `json:"email"`
}

user := User{Name: "Alice", Age: 25, Email: "alice@example.com"}
data, _ := json.Marshal(user)
fmt.Println(string(data))
// {"name":"Alice","age":25,"email":"alice@example.com"}

3.2 忽略字段 #

go
type User struct {
    Name     string `json:"name"`
    Password string `json:"-"`  // 序列化时忽略
}

3.3 omitempty #

字段为零值时忽略:

go
type User struct {
    Name  string `json:"name"`
    Email string `json:"email,omitempty"`
}

user := User{Name: "Alice"}
data, _ := json.Marshal(user)
fmt.Println(string(data))
// {"name":"Alice"}

3.4 字符串选项 #

将数值转为字符串:

go
type Data struct {
    Number int `json:"number,string"`
}

data := Data{Number: 42}
result, _ := json.Marshal(data)
fmt.Println(string(result))
// {"number":"42"}

四、XML标签 #

4.1 基本用法 #

go
type Person struct {
    XMLName xml.Name `xml:"person"`
    Name    string   `xml:"name"`
    Age     int      `xml:"age"`
}

p := Person{Name: "Alice", Age: 25}
data, _ := xml.Marshal(p)
fmt.Println(string(data))
// <person><name>Alice</name><age>25</age></person>

4.2 属性 #

go
type Person struct {
    XMLName xml.Name `xml:"person"`
    ID      int      `xml:"id,attr"`
    Name    string   `xml:"name"`
}

4.3 嵌套元素 #

go
type Address struct {
    City string `xml:"city"`
}

type Person struct {
    Name    string  `xml:"name"`
    Address Address `xml:"address"`
}

五、数据库标签 #

5.1 GORM标签 #

go
type User struct {
    ID        uint      `gorm:"primaryKey"`
    Name      string    `gorm:"size:100;not null"`
    Email     string    `gorm:"uniqueIndex"`
    CreatedAt time.Time `gorm:"autoCreateTime"`
}

5.2 常用GORM标签 #

标签 说明
primaryKey 主键
uniqueIndex 唯一索引
index 普通索引
not null 非空
size 字符串长度
default 默认值

六、验证标签 #

6.1 validator库 #

go
type User struct {
    Name  string `validate:"required,min=2,max=100"`
    Email string `validate:"required,email"`
    Age   int    `validate:"gte=0,lte=130"`
}

func main() {
    validate := validator.New()
    user := User{Name: "A", Email: "invalid", Age: 200}
    
    err := validate.Struct(user)
    if err != nil {
        fmt.Println(err)
    }
}

6.2 常用验证标签 #

标签 说明
required 必填
email 邮箱格式
url URL格式
min, max 最小/最大值
len 长度
oneof 枚举值

七、反射获取标签 #

7.1 基本用法 #

go
type User struct {
    Name string `json:"name" validate:"required"`
}

func main() {
    t := reflect.TypeOf(User{})
    field, _ := t.FieldByName("Name")
    
    fmt.Println(field.Tag.Get("json"))     // name
    fmt.Println(field.Tag.Get("validate")) // required
}

7.2 遍历所有字段 #

go
func printTags(v interface{}) {
    t := reflect.TypeOf(v)
    
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        fmt.Printf("Field: %s, Tag: %s\n", 
            field.Name, field.Tag)
    }
}

7.3 Lookup方法 #

go
tag := field.Tag.Lookup("json")
if ok {
    fmt.Println("json tag:", tag)
}

八、自定义标签 #

8.1 定义标签 #

go
type User struct {
    Name string `custom:"user_name" format:"upper"`
}

8.2 解析自定义标签 #

go
func processCustomTag(v interface{}) {
    t := reflect.TypeOf(v)
    
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        if custom := field.Tag.Get("custom"); custom != "" {
            fmt.Printf("Custom name for %s: %s\n", 
                field.Name, custom)
        }
    }
}

8.3 实际应用 #

go
type FieldMapping struct {
    FieldName  string
    ColumnName string
    Required   bool
}

func ParseModel(v interface{}) []FieldMapping {
    t := reflect.TypeOf(v)
    var mappings []FieldMapping
    
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        mapping := FieldMapping{
            FieldName:  field.Name,
            ColumnName: field.Tag.Get("db"),
            Required:   field.Tag.Get("required") == "true",
        }
        mappings = append(mappings, mapping)
    }
    return mappings
}

九、实际应用 #

9.1 配置映射 #

go
type Config struct {
    Host     string `config:"host" default:"localhost"`
    Port     int    `config:"port" default:"8080"`
    Database string `config:"database" default:"mydb"`
}

func LoadConfig(cfg interface{}) error {
    v := reflect.ValueOf(cfg).Elem()
    t := v.Type()
    
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        key := field.Tag.Get("config")
        def := field.Tag.Get("default")
        
        if val := os.Getenv(key); val != "" {
            v.Field(i).SetString(val)
        } else if def != "" {
            v.Field(i).SetString(def)
        }
    }
    return nil
}

9.2 表单绑定 #

go
type LoginForm struct {
    Username string `form:"username" validate:"required"`
    Password string `form:"password" validate:"required,min=6"`
}

func BindForm(r *http.Request, form interface{}) error {
    v := reflect.ValueOf(form).Elem()
    t := v.Type()
    
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        formKey := field.Tag.Get("form")
        if formKey != "" {
            val := r.FormValue(formKey)
            v.Field(i).SetString(val)
        }
    }
    return nil
}

十、最佳实践 #

10.1 标签命名规范 #

go
// 好
type User struct {
    Name string `json:"name" db:"name"`
}

// 避免
type User struct {
    Name string `json:"user_name_in_json"`
}

10.2 保持一致性 #

go
type User struct {
    ID    int    `json:"id" db:"id"`
    Name  string `json:"name" db:"name"`
    Email string `json:"email" db:"email"`
}

10.3 文档化标签 #

go
type User struct {
    Name string `json:"name" validate:"required,min=2"`
    // Name is the user's display name (2-100 characters)
}

十一、总结 #

标签要点:

标签 用途
json JSON序列化
xml XML序列化
gorm 数据库ORM
validate 数据验证
form 表单绑定

关键点:

  1. 元数据:标签为字段添加元数据
  2. 反射读取:通过reflect包读取标签
  3. 标准库支持:json、xml等标准库支持标签
  4. 第三方库:gorm、validator等广泛使用标签
  5. 自定义标签:可以定义自己的标签

准备好学习接口了吗?让我们进入下一章!

最后更新:2026-03-26