From 96818a206e4583859aef3a11c220ed56abe24bf6 Mon Sep 17 00:00:00 2001 From: gazebo Date: Fri, 24 May 2019 16:43:21 +0800 Subject: [PATCH] - utils_reflect --- utils/utils_reflect.go | 59 +++++++++++++++++++++++++++++++++++++ utils/utils_reflect_test.go | 24 +++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 utils/utils_reflect.go create mode 100644 utils/utils_reflect_test.go diff --git a/utils/utils_reflect.go b/utils/utils_reflect.go new file mode 100644 index 00000000..56119646 --- /dev/null +++ b/utils/utils_reflect.go @@ -0,0 +1,59 @@ +package utils + +import ( + "reflect" + "strings" +) + +// 得到一个结构体(或指向结构体的指针)中其成员(tag指定,缺省是字段名)的路径(嵌入结构体或指向结构指针会被展开) +func GetStructObjNameIndex(obj interface{}, tag string) map[string][]int { + objType := reflect.TypeOf(obj) + return GetStructNameIndex(objType, tag) +} + +func GetStructNameIndex(objType reflect.Type, tag string) (nameIndex map[string][]int) { + if objType.Kind() == reflect.Ptr { + objType = objType.Elem() + } + if objType.Kind() != reflect.Struct { + panic("obj must be struct obj or pointer to struct of obj!") + } + nameIndex = make(map[string][]int) + for i := 0; i < objType.NumField(); i++ { + structField := objType.Field(i) + fieldType := structField.Type + + if IndirectType(fieldType).Kind() == reflect.Struct && IsFieldEmbedded(&structField) { // 嵌入 + subNameIndex := GetStructNameIndex(fieldType, tag) + for k, v := range subNameIndex { + nameIndex[k] = append([]int{i}, v...) + } + } else { + tagName := structField.Name + if tag != "" { + tagName2 := strings.Split(structField.Tag.Get(tag), ",")[0] + if tagName2 == "-" { + tagName = "" // 忽略 + } else if tagName2 != "" { + tagName = tagName2 + } + } + if tagName != "" { + nameIndex[tagName] = []int{i} + } + } + } + return nameIndex +} + +// 判断成员是否是嵌入的,依据是成员名与类型名相同 +func IsFieldEmbedded(structField *reflect.StructField) bool { + return structField.Name == IndirectType(structField.Type).Name() +} + +func IndirectType(objType reflect.Type) reflect.Type { + if objType.Kind() == reflect.Ptr { + objType = objType.Elem() + } + return objType +} diff --git a/utils/utils_reflect_test.go b/utils/utils_reflect_test.go new file mode 100644 index 00000000..9398f43a --- /dev/null +++ b/utils/utils_reflect_test.go @@ -0,0 +1,24 @@ +package utils + +import ( + "reflect" + "testing" +) + +func TestReflect(t *testing.T) { + type SubXXXX struct { + IntData int + StrData string + } + type XXXX struct { + SubXXXX + A int + B string `json:"b"` + } + + x := XXXX{} + typeX := reflect.TypeOf(x) + field := typeX.Field(0) + t.Log(IsFieldEmbedded(&field)) + t.Log(Format4Output(GetStructObjNameIndex(&x, ""), false)) +}