github.com/zhongdalu/gf@v1.0.0/g/util/gconv/gconv_map.go (about) 1 // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). 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/zhongdalu/gf. 6 7 package gconv 8 9 import ( 10 "reflect" 11 "strings" 12 13 "github.com/zhongdalu/gf/g/internal/empty" 14 "github.com/zhongdalu/gf/g/internal/strutils" 15 ) 16 17 // Map converts any variable <value> to map[string]interface{}. 18 // 19 // If the parameter <value> is not a map/struct/*struct type, then the conversion will fail and returns nil. 20 // 21 // If <value> is a struct/*struct object, the second parameter <tags> specifies the most priority 22 // tags that will be detected, otherwise it detects the tags in order of: gconv, json, and then the field name. 23 func Map(value interface{}, tags ...string) map[string]interface{} { 24 if value == nil { 25 return nil 26 } 27 if r, ok := value.(map[string]interface{}); ok { 28 return r 29 } else { 30 // Only assert the common combination of types, and finally it uses reflection. 31 m := make(map[string]interface{}) 32 switch value.(type) { 33 case map[interface{}]interface{}: 34 for k, v := range value.(map[interface{}]interface{}) { 35 m[String(k)] = v 36 } 37 case map[interface{}]string: 38 for k, v := range value.(map[interface{}]string) { 39 m[String(k)] = v 40 } 41 case map[interface{}]int: 42 for k, v := range value.(map[interface{}]int) { 43 m[String(k)] = v 44 } 45 case map[interface{}]uint: 46 for k, v := range value.(map[interface{}]uint) { 47 m[String(k)] = v 48 } 49 case map[interface{}]float32: 50 for k, v := range value.(map[interface{}]float32) { 51 m[String(k)] = v 52 } 53 case map[interface{}]float64: 54 for k, v := range value.(map[interface{}]float64) { 55 m[String(k)] = v 56 } 57 case map[string]bool: 58 for k, v := range value.(map[string]bool) { 59 m[k] = v 60 } 61 case map[string]int: 62 for k, v := range value.(map[string]int) { 63 m[k] = v 64 } 65 case map[string]uint: 66 for k, v := range value.(map[string]uint) { 67 m[k] = v 68 } 69 case map[string]float32: 70 for k, v := range value.(map[string]float32) { 71 m[k] = v 72 } 73 case map[string]float64: 74 for k, v := range value.(map[string]float64) { 75 m[k] = v 76 } 77 case map[int]interface{}: 78 for k, v := range value.(map[int]interface{}) { 79 m[String(k)] = v 80 } 81 case map[int]string: 82 for k, v := range value.(map[int]string) { 83 m[String(k)] = v 84 } 85 case map[uint]string: 86 for k, v := range value.(map[uint]string) { 87 m[String(k)] = v 88 } 89 // Not a common type, use reflection 90 default: 91 rv := reflect.ValueOf(value) 92 kind := rv.Kind() 93 // If it is a pointer, we should find its real data type. 94 if kind == reflect.Ptr { 95 rv = rv.Elem() 96 kind = rv.Kind() 97 } 98 switch kind { 99 case reflect.Map: 100 ks := rv.MapKeys() 101 for _, k := range ks { 102 m[String(k.Interface())] = rv.MapIndex(k).Interface() 103 } 104 case reflect.Struct: 105 rt := rv.Type() 106 name := "" 107 tagArray := structTagPriority 108 switch len(tags) { 109 case 0: 110 // No need handle. 111 case 1: 112 tagArray = append(strings.Split(tags[0], ","), structTagPriority...) 113 default: 114 tagArray = append(tags, structTagPriority...) 115 } 116 for i := 0; i < rv.NumField(); i++ { 117 // Only convert the public attributes. 118 fieldName := rt.Field(i).Name 119 if !strutils.IsLetterUpper(fieldName[0]) { 120 continue 121 } 122 name = "" 123 fieldTag := rt.Field(i).Tag 124 for _, tag := range tagArray { 125 if name = fieldTag.Get(tag); name != "" { 126 break 127 } 128 } 129 if name == "" { 130 name = strings.TrimSpace(fieldName) 131 } else { 132 // Support json tag feature: -, omitempty 133 name = strings.TrimSpace(name) 134 if name == "-" { 135 continue 136 } 137 array := strings.Split(name, ",") 138 if len(array) > 1 { 139 switch strings.TrimSpace(array[1]) { 140 case "omitempty": 141 if empty.IsEmpty(rv.Field(i).Interface()) { 142 continue 143 } else { 144 name = strings.TrimSpace(array[0]) 145 } 146 default: 147 name = strings.TrimSpace(array[0]) 148 } 149 } 150 } 151 m[name] = rv.Field(i).Interface() 152 } 153 default: 154 return nil 155 } 156 } 157 return m 158 } 159 } 160 161 // MapDeep do Map function recursively. 162 // See Map. 163 func MapDeep(value interface{}, tags ...string) map[string]interface{} { 164 data := Map(value, tags...) 165 for key, value := range data { 166 rv := reflect.ValueOf(value) 167 kind := rv.Kind() 168 if kind == reflect.Ptr { 169 rv = rv.Elem() 170 kind = rv.Kind() 171 } 172 switch kind { 173 case reflect.Struct: 174 delete(data, key) 175 for k, v := range MapDeep(value, tags...) { 176 data[k] = v 177 } 178 } 179 } 180 return data 181 }