github.com/gogf/gf@v1.16.9/util/gconv/gconv_maptomaps.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package gconv 8 9 import ( 10 "github.com/gogf/gf/errors/gcode" 11 "github.com/gogf/gf/errors/gerror" 12 "github.com/gogf/gf/internal/json" 13 "reflect" 14 ) 15 16 // MapToMaps converts any slice type variable `params` to another map slice type variable `pointer`. 17 // See doMapToMaps. 18 func MapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) error { 19 return doMapToMaps(params, pointer, mapping...) 20 } 21 22 // MapToMapsDeep converts any slice type variable `params` to another map slice type variable 23 // `pointer` recursively. 24 // Deprecated, use MapToMaps instead. 25 func MapToMapsDeep(params interface{}, pointer interface{}, mapping ...map[string]string) error { 26 return doMapToMaps(params, pointer, mapping...) 27 } 28 29 // doMapToMaps converts any map type variable `params` to another map slice variable `pointer`. 30 // 31 // The parameter `params` can be type of []map, []*map, []struct, []*struct. 32 // 33 // The parameter `pointer` should be type of []map, []*map. 34 // 35 // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes 36 // sense only if the item of `params` is type struct. 37 func doMapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) { 38 // If given `params` is JSON, it then uses json.Unmarshal doing the converting. 39 switch r := params.(type) { 40 case []byte: 41 if json.Valid(r) { 42 if rv, ok := pointer.(reflect.Value); ok { 43 if rv.Kind() == reflect.Ptr { 44 return json.UnmarshalUseNumber(r, rv.Interface()) 45 } 46 } else { 47 return json.UnmarshalUseNumber(r, pointer) 48 } 49 } 50 case string: 51 if paramsBytes := []byte(r); json.Valid(paramsBytes) { 52 if rv, ok := pointer.(reflect.Value); ok { 53 if rv.Kind() == reflect.Ptr { 54 return json.UnmarshalUseNumber(paramsBytes, rv.Interface()) 55 } 56 } else { 57 return json.UnmarshalUseNumber(paramsBytes, pointer) 58 } 59 } 60 } 61 // Params and its element type check. 62 var ( 63 paramsRv reflect.Value 64 paramsKind reflect.Kind 65 ) 66 if v, ok := params.(reflect.Value); ok { 67 paramsRv = v 68 } else { 69 paramsRv = reflect.ValueOf(params) 70 } 71 paramsKind = paramsRv.Kind() 72 if paramsKind == reflect.Ptr { 73 paramsRv = paramsRv.Elem() 74 paramsKind = paramsRv.Kind() 75 } 76 if paramsKind != reflect.Array && paramsKind != reflect.Slice { 77 return gerror.NewCode(gcode.CodeInvalidParameter, "params should be type of slice, eg: []map/[]*map/[]struct/[]*struct") 78 } 79 var ( 80 paramsElem = paramsRv.Type().Elem() 81 paramsElemKind = paramsElem.Kind() 82 ) 83 if paramsElemKind == reflect.Ptr { 84 paramsElem = paramsElem.Elem() 85 paramsElemKind = paramsElem.Kind() 86 } 87 if paramsElemKind != reflect.Map && paramsElemKind != reflect.Struct && paramsElemKind != reflect.Interface { 88 return gerror.NewCodef(gcode.CodeInvalidParameter, "params element should be type of map/*map/struct/*struct, but got: %s", paramsElemKind) 89 } 90 // Empty slice, no need continue. 91 if paramsRv.Len() == 0 { 92 return nil 93 } 94 // Pointer and its element type check. 95 var ( 96 pointerRv = reflect.ValueOf(pointer) 97 pointerKind = pointerRv.Kind() 98 ) 99 for pointerKind == reflect.Ptr { 100 pointerRv = pointerRv.Elem() 101 pointerKind = pointerRv.Kind() 102 } 103 if pointerKind != reflect.Array && pointerKind != reflect.Slice { 104 return gerror.NewCode(gcode.CodeInvalidParameter, "pointer should be type of *[]map/*[]*map") 105 } 106 var ( 107 pointerElemType = pointerRv.Type().Elem() 108 pointerElemKind = pointerElemType.Kind() 109 ) 110 if pointerElemKind == reflect.Ptr { 111 pointerElemKind = pointerElemType.Elem().Kind() 112 } 113 if pointerElemKind != reflect.Map { 114 return gerror.NewCode(gcode.CodeInvalidParameter, "pointer element should be type of map/*map") 115 } 116 defer func() { 117 // Catch the panic, especially the reflect operation panics. 118 if exception := recover(); exception != nil { 119 if e, ok := exception.(errorStack); ok { 120 err = e 121 } else { 122 err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception) 123 } 124 } 125 }() 126 var ( 127 pointerSlice = reflect.MakeSlice(pointerRv.Type(), paramsRv.Len(), paramsRv.Len()) 128 ) 129 for i := 0; i < paramsRv.Len(); i++ { 130 var item reflect.Value 131 if pointerElemType.Kind() == reflect.Ptr { 132 item = reflect.New(pointerElemType.Elem()) 133 if err = MapToMap(paramsRv.Index(i).Interface(), item, mapping...); err != nil { 134 return err 135 } 136 pointerSlice.Index(i).Set(item) 137 } else { 138 item = reflect.New(pointerElemType) 139 if err = MapToMap(paramsRv.Index(i).Interface(), item, mapping...); err != nil { 140 return err 141 } 142 pointerSlice.Index(i).Set(item.Elem()) 143 } 144 } 145 pointerRv.Set(pointerSlice) 146 return 147 }