本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Golang Tag语法
Tag格式
tag被定义在结构体字段的后面,以字符串的形式出现,如下所示:
type T struct {
f1 string "f one"
f2 string
f3 string `f three`
f4, f5 int64 `f four and five`
}
要注意,不管是双引号还是反引号,都可以用来当tag。如果结构体字段在定义的时候,两个字段共用一个属性,那么这个tag会被附在两个名字上,像上述代码中的f1,f5一样。
键值对
Tags可以由键值对来组成,通过空格符来分割键值 —key1:"value1" key2:"value2" key3:"value3"。如果Tags格式没问题的话,我们可以通过Lookup或者Get来获取键值对的值。
Lookup回传两个值,对应的值和是否找到。
Get只回传一个值,即对应的那个值,如果没有找到就返回空。
package main
import (
"fmt"
"reflect"
)
type Food struct {
Apple string `fruit:"apple"`
Tomato string `vegetable:"tomato"`
}
func main() {
t := reflect.TypeOf(Food{})
f, _ := t.FieldByName("Apple")
fmt.Println(f.Tag)
// Tag.Lookup
v, ok := f.Tag.Lookup("fruit")
fmt.Printf("%s, %t\n", v, ok)
// Tag.Get
v = f.Tag.Get("fruit")
fmt.Println(v)
}
运行结果:
fruit:"apple"
apple, true
apple
Tag的使用
json
在golang中,命名都是推荐用驼峰方式,并且在首字母大小写有特殊的语法含义:包外无法引用。但是由于经常需要和其它的系统进行数据交互,例如转成json格式,存储到mongodb啊等等。这个时候如果用属性名来作为键值可能不一定会符合项目要求。 而通过Tag,我们可以在转换成其它格式的时候,使用其中定义的字段作为键值。 例如:
package main
import (
"encoding/json"
"fmt"
)
type User struct {
UserId int `json:"user_id"`
UserName string `json:"user_name"`
}
func main() {
u := &User{UserId: 1, UserName: "张三"}
j, _ := json.Marshal(u)
fmt.Println(string(j))
}
输出结果:
{"user_id":1,"user_name":"张三"}
ORM
ORM是指将关系型数据库中的记录映射为对象,以对象的形式展现。我们可以把对数据库的操作转化为对对象的操作。
| 面向对象的概念 | 面向关系概念 |
|---|---|
| 类 | 表 |
| 对象 | 表的行(记录) |
| 属性 | 表的列(字段) |
对应到golang中,就是把对关系型数据库的操作转化为对结构体的操作。
我们以GORM框架来举例,在GORM中,与数据表进行映射的结构体我们称之为模型(Models)。
回归到Tag,在数据表中定义一个字段时,我们通常会在字段的末尾加上一些额外信息,比如约束、列大小等等。映射到Models中,就需要使用Tag来设置相应的信息。
例如下面这个Models:
type User struct {
gorm.Model
Name string
Age sql.NullInt64
Birthday *time.Time
Email string `gorm:"type:varchar(100);unique_index"`
Role string `gorm:"size:255"` // 设置字段大小为255
MemberNumber *string `gorm:"unique;not null"` // 设置会员号(member number)唯一并且不为空
Num int `gorm:"AUTO_INCREMENT"` // 设置 num 为自增类型
Address string `gorm:"index:addr"` // 给address字段创建名为addr的索引
IgnoreMe int `gorm:"-"` // 忽略本字段
}
GORM框架支持很多结构体Tag,具体可以查看这篇博文: