當我們在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 anyfieldName stringtagkey stringexpected 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