当我们在go语言中定义结构体的时候, 经常需要给某些字段打上一个Tag标签, 如 Name string `json:"name"·` , 那这个标签有和作用呢? 这个作用可大了,最为常用的是json序列化和反序列化, 还有各种ORM 的实体对象定义,这个Tag可是必不可少的。 今天给大家介绍的这个函数就是用来获取这个Tag中定义的值的函数, 废话不多说,直接上代码:
获取结构体Struct标签Tag的值函数GetStructTagVal
import (
"fmt"
"reflect"
)
// 获取一个结构体TAG中的指定tagKey的值, 如果没有对应的tagKey则返回空字符串和相应的错误信息
// structObj 结构体对象
// fieldName 结构体中定义的字段名称 区分大小写
// tagkey 结构体字段的Tag中定义的key,
//
// 如: 结构体字段定义 Name string `json:"name" orm:"varchar(50) comment('名称')"`
// 这里的tagKey就是 json 或者 orm
// 获取到的值就是tagKey后面的双引号内的值,如tagkey为 orm 获取的值就是 varchar(50) comment('名称')
//
// @author tekintian <tekintian@gmail.com>
func GetStructTagVal(structObj interface{}, fieldName, tagKey string) (string, error) {
refType := reflect.TypeOf(structObj)
if refType.Kind() != reflect.Struct { //传入的数据非结构体类型,直接返回
return "", fmt.Errorf("传入参数 %v 的类型为 %T , 非结构体类型!", structObj, structObj)
}
if fieldObj, ok := refType.FieldByName(fieldName); ok {
// 这里的sfield.Tag.Get(tagKey) 直接返回的是一个字符串
if tagVal, isOk := fieldObj.Tag.Lookup(tagKey); isOk {
return tagVal, nil
} else {
return "", fmt.Errorf("在结构体 %v 字段 %v 中未找到tagkey为 %v 的定义", refType.Name(), fieldName, tagKey)
}
}
return "", fmt.Errorf("在结构体 %v 中未找到 %v 字段的定义", refType.Name(), fieldName)
}
// 根据结构体StructField获取tag标签的值 没有对应的tagkey将返回空字符串
// - field: 通过反射获取的字段对应的结构体字段对象 reflect.TypeOf(structObj).FieldByName(fieldName)
// - tagKey: tag标签的key
func GetStructTagValByStructField(fieldObj reflect.StructField, tagKey string) string {
return fieldObj.Tag.Get(tagKey)
}
GetStructTagVal函数测试用例:
import (
"testing"
)
// GetStructTagVal单元测试用例
// @author tekintian <tekintian@gmail.com>
func TestGetStructTagVal(t *testing.T) {
// 定义测试用例数据
cases := []struct { // 测试用例输入参数和期望输出参数定义
structObj any
fieldName string
tagkey string
expected string // 预期结果
}{
{structObj: Person{}, fieldName: "Name", tagkey: "myorm", expected: "varchar(25) notnull unique 'usr_name' comment('姓名')"},
{structObj: Person{}, fieldName: "age", tagkey: "json", expected: "age"},
// 异常测试用例数据定义
{structObj: Person{}, fieldName: "sex", tagkey: "json", expected: "在结构体 Person 中未找到 sex 字段的定义"},
{structObj: Person{}, fieldName: "age", tagkey: "json1", expected: "在结构体 Person 字段 age 中未找到tagkey为 json1 的定义"},
{structObj: 123, fieldName: "x", tagkey: "y", expected: "传入参数 123 的类型为 int , 非结构体类型!"}, // 这个直接就返回异常了
}
for _, v := range cases {
t.Run(v.fieldName, func(t *testing.T) {
tagVal, err := GetStructTagVal(v.structObj, v.fieldName, v.tagkey)
// 这里如果异常信息不为空,且异常信息 等于期望的异常 或者 输出结果等于期望结果 测试成功
if (err != nil && err.Error() == v.expected) || tagVal == v.expected {
t.Log(tagVal) // 测试通过,打印日志信息
} else {
// 测试失败的情况
// 有异常且是非期望的异常
if err != nil {
t.Fatal(err) // 测试失败,打印异常信息
} else {
// 结果不等于预期 测试失败
t.Fatalf("test failed, expected '%v', got '%v'", v.expected, tagVal)
}
}
})
}
}