go语言版本的 array_column 方法
Posted zhongweikang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言版本的 array_column 方法相关的知识,希望对你有一定的参考价值。
功能1:提取 []struct 中 column 列。desk中存储为 slice
功能2:提取 []struct 中的 index 列作为 key,column列作为值。 desk 中存储为map
参数说明 :
@param desk [slice|map] 指针类型,方法最终的存储位置
@param input []struct,待转换的结构体切片
@param columnKey string
@param indexKey string
go语言代码实现:
1 package array_column_test 2 3 import ( 4 "reflect" 5 "fmt" 6 "errors" 7 ) 8 9 func StructColumn(desk, input interface{}, columnKey, indexKey string) (err error) { 10 deskValue := reflect.ValueOf(desk) 11 if deskValue.Kind() != reflect.Ptr { 12 return errors.New("desk must be ptr") 13 } 14 15 rv := reflect.ValueOf(input) 16 if rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array { 17 return errors.New("input must be map slice or array") 18 } 19 20 rt := reflect.TypeOf(input) 21 if rt.Elem().Kind() != reflect.Struct { 22 return errors.New("input‘s elem must be struct") 23 } 24 25 if len(indexKey) > 0 { 26 return structIndexColumn(desk, input, columnKey, indexKey) 27 } 28 return structColumn(desk, input, columnKey) 29 } 30 31 func structColumn(desk, input interface{}, columnKey string) (err error) { 32 if len(columnKey) == 0 { 33 return errors.New("columnKey cannot not be empty") 34 } 35 36 deskElemType := reflect.TypeOf(desk).Elem() 37 if deskElemType.Kind() != reflect.Slice { 38 return errors.New("desk must be slice") 39 } 40 41 rv := reflect.ValueOf(input) 42 rt := reflect.TypeOf(input) 43 44 var columnVal reflect.Value 45 deskValue := reflect.ValueOf(desk) 46 direct := reflect.Indirect(deskValue) 47 48 for i := 0; i < rv.Len(); i++ { 49 columnVal, err = findStructValByColumnKey(rv.Index(i), rt.Elem(), columnKey) 50 if err != nil { 51 return 52 } 53 if deskElemType.Elem().Kind() != columnVal.Kind() { 54 return errors.New(fmt.Sprintf("your slice must be []%s", columnVal.Kind())) 55 } 56 57 direct.Set(reflect.Append(direct, columnVal)) 58 } 59 return 60 } 61 62 func findStructValByColumnKey(curVal reflect.Value, elemType reflect.Type, columnKey string) (columnVal reflect.Value, err error) { 63 columnExist := false 64 for i := 0; i < elemType.NumField(); i++ { 65 curField := curVal.Field(i) 66 if elemType.Field(i).Name == columnKey { 67 columnExist = true 68 columnVal = curField 69 continue 70 } 71 } 72 if !columnExist { 73 return columnVal, errors.New(fmt.Sprintf("columnKey %s not found in %s‘s field", columnKey, elemType)) 74 } 75 return 76 } 77 78 func structIndexColumn(desk, input interface{}, columnKey, indexKey string) (err error) { 79 deskValue := reflect.ValueOf(desk) 80 if deskValue.Elem().Kind() != reflect.Map { 81 return errors.New("desk must be map") 82 } 83 deskElem := deskValue.Type().Elem() 84 if len(columnKey) == 0 && deskElem.Elem().Kind() != reflect.Struct { 85 return errors.New(fmt.Sprintf("desk‘s elem expect struct, got %s", deskElem.Elem().Kind())) 86 } 87 88 rv := reflect.ValueOf(input) 89 rt := reflect.TypeOf(input) 90 elemType := rt.Elem() 91 92 var indexVal, columnVal reflect.Value 93 direct := reflect.Indirect(deskValue) 94 mapReflect := reflect.MakeMap(deskElem) 95 deskKey := deskValue.Type().Elem().Key() 96 97 for i := 0; i < rv.Len(); i++ { 98 curVal := rv.Index(i) 99 indexVal, columnVal, err = findStructValByIndexKey(curVal, elemType, indexKey, columnKey) 100 if err != nil { 101 return 102 } 103 if deskKey.Kind() != indexVal.Kind() { 104 return errors.New(fmt.Sprintf("cant‘t convert %s to %s, your map‘key must be %s", indexVal.Kind(), deskKey.Kind(), indexVal.Kind())) 105 } 106 if len(columnKey) == 0 { 107 mapReflect.SetMapIndex(indexVal, curVal) 108 direct.Set(mapReflect) 109 } else { 110 if deskElem.Elem().Kind() != columnVal.Kind() { 111 return errors.New(fmt.Sprintf("your map must be map[%s]%s", indexVal.Kind(), columnVal.Kind())) 112 } 113 mapReflect.SetMapIndex(indexVal, columnVal) 114 direct.Set(mapReflect) 115 } 116 } 117 return 118 } 119 120 func findStructValByIndexKey(curVal reflect.Value, elemType reflect.Type, indexKey, columnKey string) (indexVal, columnVal reflect.Value, err error) { 121 indexExist := false 122 columnExist := false 123 for i := 0; i < elemType.NumField(); i++ { 124 curField := curVal.Field(i) 125 if elemType.Field(i).Name == indexKey { 126 switch curField.Kind() { 127 case reflect.String, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int, reflect.Float64, reflect.Float32: 128 indexExist = true 129 indexVal = curField 130 default: 131 return indexVal, columnVal, errors.New("indexKey must be int float or string") 132 } 133 } 134 if elemType.Field(i).Name == columnKey { 135 columnExist = true 136 columnVal = curField 137 continue 138 } 139 } 140 if !indexExist { 141 return indexVal, columnVal, errors.New(fmt.Sprintf("indexKey %s not found in %s‘s field", indexKey, elemType)) 142 } 143 if len(columnKey) > 0 && !columnExist { 144 return indexVal, columnVal, errors.New(fmt.Sprintf("columnKey %s not found in %s‘s field", columnKey, elemType)) 145 } 146 return 147 }
测试
1 func TestBindFromArrayColumn(t *testing.T) { 2 user1 := User{ 3 ID: 1, 4 NAME: "zwk", 5 } 6 user2 := User{ 7 ID: 2, 8 NAME: "zzz", 9 } 10 var list3 []User 11 list3 = append(list3, user1) 12 list3 = append(list3, user2) 13 14 var userMap map[int]string 15 StructColumn(&userMap, list3, "NAME", "ID") 16 fmt.Printf("%#v ", userMap) 17 18 var userMap1 map[int]User 19 StructColumn(&userMap1, list3, "", "ID") 20 fmt.Printf("%#v ", userMap1) 21 22 var userSlice []int 23 StructColumn(&userSlice, list3, "ID", "") 24 fmt.Printf("%#v ", userSlice) 25 }
测试结果
map[int]string{1:"zwk", 2:"zzz"} map[int]User{1:User{ID:1, NAME:"zwk"}, 2:User{ID:2, NAME:"zzz"}} []int{1, 2}
以上是关于go语言版本的 array_column 方法的主要内容,如果未能解决你的问题,请参考以下文章