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 }
View Code

 

 测试

技术图片
 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 }
View Code

测试结果

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 方法的主要内容,如果未能解决你的问题,请参考以下文章

《Go语言精进之路》读书笔记 | 选择适当的Go语言版本

php内置函数分析之array_column()

《Go语言精进之路》读书笔记 | 汇总

Fabric链码入门案例(go语言版本)

GO语言(二十九):模糊测试(下)-

php 5.5使用 array_column的方法