From c195bf7819ceef22b5acac4c2634c79ceb02d6d7 Mon Sep 17 00:00:00 2001 From: yangzm <18675616014@163.com> Date: Wed, 22 Dec 2021 14:27:31 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E6=9D=A8=E3=80=91=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E4=BD=93=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- struct.go | 149 +++++++++++++++++++++++++++++++++++++++++++++++++ struct_test.go | 47 ++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 struct.go create mode 100644 struct_test.go diff --git a/struct.go b/struct.go new file mode 100644 index 0000000..b17a3c6 --- /dev/null +++ b/struct.go @@ -0,0 +1,149 @@ +package helper + +import ( + "errors" + "fmt" + "reflect" +) + +// 结构体泛型提取关键数据 +// desk结构体, input提取数据源, columnKey提取的字段,indexKey提取的下标 +func StructColumn(desk, input interface{}, columnKey, indexKey string) (err error) { + deskValue := reflect.ValueOf(desk) + if deskValue.Kind() != reflect.Ptr { + return errors.New("desk must be ptr") + } + + rv := reflect.ValueOf(input) + if rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array { + return errors.New("input must be map slice or array") + } + + rt := reflect.TypeOf(input) + if rt.Elem().Kind() != reflect.Struct { + return errors.New("input's elem must be struct") + } + + if len(indexKey) > 0 { + return structIndexColumn(desk, input, columnKey, indexKey) + } + return structColumn(desk, input, columnKey) +} + +func structColumn(desk, input interface{}, columnKey string) (err error) { + if len(columnKey) == 0 { + return errors.New("columnKey cannot not be empty") + } + + deskElemType := reflect.TypeOf(desk).Elem() + if deskElemType.Kind() != reflect.Slice { + return errors.New("desk must be slice") + } + + rv := reflect.ValueOf(input) + rt := reflect.TypeOf(input) + + var columnVal reflect.Value + deskValue := reflect.ValueOf(desk) + direct := reflect.Indirect(deskValue) + + for i := 0; i < rv.Len(); i++ { + columnVal, err = findStructValByColumnKey(rv.Index(i), rt.Elem(), columnKey) + if err != nil { + return + } + if deskElemType.Elem().Kind() != columnVal.Kind() { + return errors.New(fmt.Sprintf("your slice must be []%s", columnVal.Kind())) + } + + direct.Set(reflect.Append(direct, columnVal)) + } + return +} + +func findStructValByColumnKey(curVal reflect.Value, elemType reflect.Type, columnKey string) (columnVal reflect.Value, err error) { + columnExist := false + for i := 0; i < elemType.NumField(); i++ { + curField := curVal.Field(i) + if elemType.Field(i).Name == columnKey { + columnExist = true + columnVal = curField + continue + } + } + if !columnExist { + return columnVal, errors.New(fmt.Sprintf("columnKey %s not found in %s's field", columnKey, elemType)) + } + return +} + +func structIndexColumn(desk, input interface{}, columnKey, indexKey string) (err error) { + deskValue := reflect.ValueOf(desk) + if deskValue.Elem().Kind() != reflect.Map { + return errors.New("desk must be map") + } + deskElem := deskValue.Type().Elem() + if len(columnKey) == 0 && deskElem.Elem().Kind() != reflect.Struct { + return errors.New(fmt.Sprintf("desk's elem expect struct, got %s", deskElem.Elem().Kind())) + } + + rv := reflect.ValueOf(input) + rt := reflect.TypeOf(input) + elemType := rt.Elem() + + var indexVal, columnVal reflect.Value + direct := reflect.Indirect(deskValue) + mapReflect := reflect.MakeMap(deskElem) + deskKey := deskValue.Type().Elem().Key() + + for i := 0; i < rv.Len(); i++ { + curVal := rv.Index(i) + indexVal, columnVal, err = findStructValByIndexKey(curVal, elemType, indexKey, columnKey) + if err != nil { + return + } + if deskKey.Kind() != indexVal.Kind() { + return errors.New(fmt.Sprintf("cant't convert %s to %s, your map'key must be %s", indexVal.Kind(), deskKey.Kind(), indexVal.Kind())) + } + if len(columnKey) == 0 { + mapReflect.SetMapIndex(indexVal, curVal) + direct.Set(mapReflect) + } else { + if deskElem.Elem().Kind() != columnVal.Kind() { + return errors.New(fmt.Sprintf("your map must be map[%s]%s", indexVal.Kind(), columnVal.Kind())) + } + mapReflect.SetMapIndex(indexVal, columnVal) + direct.Set(mapReflect) + } + } + return +} + +func findStructValByIndexKey(curVal reflect.Value, elemType reflect.Type, indexKey, columnKey string) (indexVal, columnVal reflect.Value, err error) { + indexExist := false + columnExist := false + for i := 0; i < elemType.NumField(); i++ { + curField := curVal.Field(i) + if elemType.Field(i).Name == indexKey { + switch curField.Kind() { + case reflect.String, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int, reflect.Float64, reflect.Float32: + indexExist = true + indexVal = curField + default: + return indexVal, columnVal, errors.New("indexKey must be int float or string") + } + } + if elemType.Field(i).Name == columnKey { + columnExist = true + columnVal = curField + continue + } + } + if !indexExist { + return indexVal, columnVal, errors.New(fmt.Sprintf("indexKey %s not found in %s's field", indexKey, elemType)) + } + if len(columnKey) > 0 && !columnExist { + return indexVal, columnVal, errors.New(fmt.Sprintf("columnKey %s not found in %s's field", columnKey, elemType)) + } + return +} diff --git a/struct_test.go b/struct_test.go new file mode 100644 index 0000000..5088d2c --- /dev/null +++ b/struct_test.go @@ -0,0 +1,47 @@ +package helper + +import ( + "testing" +) + +type User struct { + ID int + NAME string +} + +type UserString struct { + ID string + NAME string +} + +func Test_structColumn(t *testing.T) { + user1 := UserString{ + ID: "2", + NAME: "zwk", + } + user2 := UserString{ + ID: "3", + NAME: "zzz", + } + var list3 []UserString + list3 = append(list3, user1) + list3 = append(list3, user2) + + t.Log(list3) + t.Log("---------------------") + + var userMap map[string]string + StructColumn(&userMap, list3, "NAME", "ID") + t.Logf("%#v\n", userMap) + t.Log("---------------------") + + var userMap1 map[int]UserString + StructColumn(&userMap1, list3, "", "ID") + t.Logf("%#v\n", userMap1) + t.Log("---------------------") + + var userSlice []string + StructColumn(&userSlice, list3, "ID", "") + t.Logf("%#v\n", userSlice) + t.Log("---------------------") +}