什么是 tag
正常定义结构体
type Person struct {
Name string
Age int
Addr string
}
字段上还可以再添加额外的属性,由反引号包裹的字符串,也就是 tag ,也就是标签
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Addr string `json:"addr,omitempty"`
}
那么 tag 有什么用呢,下面代码是 encoding/json 库的用法
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Addr string `json:"addr,omitempty"`
}
func main() {
p1 := Person{
Name: "Jack",
Age: 22,
}
data1, err := json.Marshal(p1)
if err != nil {
panic(err)
}
// p1 没有 Addr,就不会打印了,因为 tag 中加了 omitempty 字段
fmt.Printf("%s\n", data1)
// ================
p2 := Person{
Name: "Jack",
Age: 22,
Addr: "China",
}
data2, err := json.Marshal(p2)
if err != nil {
panic(err)
}
// p2 则会打印所有
fmt.Printf("%s\n", data2)
}
由于 Person 结构体里的 Addr 字段有 omitempty 属性,因此 encoding/json 在将对象转化 json 字符串时,只要发现对象里的 Addr 为 false, 0, 空指针,空接口,空数组,空切片,空映射,空字符串中的一种,就会被忽略。
如何定义 tag
tag 由反引号包裹,有一对或几对键值对组成,格式如下
`key01:"value01" key02:"value02" key03:"value03"`
定义完后,可以通过反射从结构体中取出 tag
- 获取字段 field
- 获取标签 tag
- 获取键值对 key :value
// 三种获取 field
field := reflect.TypeOf(obj).FieldByName("Name")
field := reflect.ValueOf(obj).Type().Field(i) // i 表示第几个字段
field := reflect.ValueOf(&obj).Elem().Type().Field(i) // i 表示第几个字段
// 获取 Tag
tag := field.Tag
// 获取键值对
labelValue := tag.Get("label")
labelValue,ok := tag.Lookup("label")
tag 用处举例:
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string `label:"Name is: "`
Age int `label:"Age is: "`
Gender string `label:"Gender is: " default:"unknown"`
}
func Print(obj interface{}) error {
// 取 Value
v := reflect.ValueOf(obj)
// 解析字段
for i := 0; i < v.NumField(); i++ {
// 取tag
field := v.Type().Field(i)
tag := field.Tag
// 解析label 和 default
label := tag.Get("label")
defaultValue := tag.Get("default")
value := fmt.Sprintf("%v", v.Field(i))
if value == "" {
// 如果没有指定值,则用默认值替代
value = defaultValue
}
fmt.Println(label + value)
}
return nil
}
func main() {
person := Person{
Name: "MING",
Age: 29,
}
err := Print(person)
if err != nil {
return
}
}
美化输出