反射操作结构体-使用Tag标签
使用Tag标签
首先,看如下这有一个练习:
Person结构体定义如下:
type Person struct {
Name string `label:"Person Name: " uppercase:"true"`
Age int `label:"Age is: "`
Sex string `label:"Sex is: "`
Description string
}
Person包含四个字段,使用一个名为lable的tag来定义打印时的标题。如果是字符串类型的字段,通过名为uppercase的tag控制是否显示字符串的大写形式(默认小写)。如:有一个Person结构体变量为:
person{Tom 29 Male Cool}
按照上面Person中tag的使用,输出结果应该为:
Person Name: TOM
Age is: 29
Sex is: male
Description: cool
即,除 TOM 名字外,其余字段,无论输入为何,输出皆为小写。
功能实现如下:
type Person struct {
Name string `label:"Person Name: " uppercase:"true"`
Age int `label:"Age is: "`
Sex string `label:"Sex is: "`
Description string
}
// 按照tag打印结构体
func PrintUseTag(ptr interface{}) error {
// 获取入参的类型
reType := reflect.TypeOf(ptr)
// 入参类型校验
if reType.Kind() != reflect.Ptr || reType.Elem().Kind() != reflect.Struct {
return fmt.Errorf("参数应该为结构体指针")
}
// 取指针指向的结构体变量
v := reflect.ValueOf(ptr).Elem()
// 解析字段, NumField() 4 个字段。
for i := 0; i < v.NumField(); i++ {
// 获取结构体字段信息
structField := v.Type().Field(i)
// 取tag
tag := structField.Tag
// 解析label tag,获取tag值
label := tag.Get("label")
if label == "" {
label = structField.Name + ": "
}
// 解析uppercase tag, 除 uppercase 标签外,全部小写输出。
value := fmt.Sprintf("%v", v.Field(i))
// 字段类型为字符串时, 判断tag值是否为真,进行大小写转换。
if structField.Type.Kind() == reflect.String {
tagVal := tag.Get("uppercase")
if tagVal == "true" {
value = strings.ToUpper(value)
} else {
value = strings.ToLower(value)
}
}
fmt.Println(label + value)
}
return nil
}
func main() {
person := Person{"Tom",29,"Male","Cool"}
PrintUseTag(&person)
}
main中初始化了一个person结构体变量,然后调用PrintUseTag函数通过反射,获取并解析tag。当字段类型为string时候,判断uppercase tag是否使用。打印每一个字段的label和value组成的字符串。Value可以是任意类型,借助于fmt包的Sprintf函数的%v,可将其他类型转化为字符串。
掌握tag的使用,我们可以使用Golang定义很多自己的工具,减少冗余代码,尤其在框架的定义中作用十分明显。