golang中通过反射获取结构体Tag标签定义的内容 函数和测试用例

当我们在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)
				}
			}
		})
	}
}

参考 reflect package - reflect - Go Packages

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值