广告平台(媒体使用)
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

map_and_struct.go 7.2 KiB

před 4 měsíci
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. package utils
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "reflect"
  6. "strconv"
  7. "strings"
  8. )
  9. func Map2Struct(vals map[string]interface{}, dst interface{}) (err error) {
  10. return Map2StructByTag(vals, dst, "json")
  11. }
  12. func Map2StructByTag(vals map[string]interface{}, dst interface{}, structTag string) (err error) {
  13. defer func() {
  14. e := recover()
  15. if e != nil {
  16. if v, ok := e.(error); ok {
  17. err = fmt.Errorf("Panic: %v", v.Error())
  18. } else {
  19. err = fmt.Errorf("Panic: %v", e)
  20. }
  21. }
  22. }()
  23. pt := reflect.TypeOf(dst)
  24. pv := reflect.ValueOf(dst)
  25. if pv.Kind() != reflect.Ptr || pv.Elem().Kind() != reflect.Struct {
  26. return fmt.Errorf("not a pointer of struct")
  27. }
  28. var f reflect.StructField
  29. var ft reflect.Type
  30. var fv reflect.Value
  31. for i := 0; i < pt.Elem().NumField(); i++ {
  32. f = pt.Elem().Field(i)
  33. fv = pv.Elem().Field(i)
  34. ft = f.Type
  35. if f.Anonymous || !fv.CanSet() {
  36. continue
  37. }
  38. tag := f.Tag.Get(structTag)
  39. name, option := parseTag(tag)
  40. if name == "-" {
  41. continue
  42. }
  43. if name == "" {
  44. name = strings.ToLower(f.Name)
  45. }
  46. val, ok := vals[name]
  47. if !ok {
  48. if option == "required" {
  49. return fmt.Errorf("'%v' not found", name)
  50. }
  51. if len(option) != 0 {
  52. val = option // default value
  53. } else {
  54. //fv.Set(reflect.Zero(ft)) // TODO set zero value or just ignore it?
  55. continue
  56. }
  57. }
  58. // convert or set value to field
  59. vv := reflect.ValueOf(val)
  60. vt := reflect.TypeOf(val)
  61. if vt.Kind() != reflect.String {
  62. // try to assign and convert
  63. if vt.AssignableTo(ft) {
  64. fv.Set(vv)
  65. continue
  66. }
  67. if vt.ConvertibleTo(ft) {
  68. fv.Set(vv.Convert(ft))
  69. continue
  70. }
  71. return fmt.Errorf("value type not match: field=%v(%v) value=%v(%v)", f.Name, ft.Kind(), val, vt.Kind())
  72. }
  73. s := strings.TrimSpace(vv.String())
  74. if len(s) == 0 && option == "required" {
  75. return fmt.Errorf("value of required argument can't not be empty")
  76. }
  77. fk := ft.Kind()
  78. // convert string to value
  79. if fk == reflect.Ptr && ft.Elem().Kind() == reflect.String {
  80. fv.Set(reflect.ValueOf(&s))
  81. continue
  82. }
  83. if fk == reflect.Ptr || fk == reflect.Struct {
  84. err = convertJsonValue(s, name, fv)
  85. } else if fk == reflect.Slice {
  86. err = convertSlice(s, f.Name, ft, fv)
  87. } else {
  88. err = convertValue(fk, s, f.Name, fv)
  89. }
  90. if err != nil {
  91. return err
  92. }
  93. continue
  94. }
  95. return nil
  96. }
  97. func Struct2Map(s interface{}) map[string]interface{} {
  98. return Struct2MapByTag(s, "json")
  99. }
  100. func Struct2MapByTag(s interface{}, tagName string) map[string]interface{} {
  101. t := reflect.TypeOf(s)
  102. v := reflect.ValueOf(s)
  103. if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
  104. t = t.Elem()
  105. v = v.Elem()
  106. }
  107. if v.Kind() != reflect.Struct {
  108. return nil
  109. }
  110. m := make(map[string]interface{})
  111. for i := 0; i < t.NumField(); i++ {
  112. fv := v.Field(i)
  113. ft := t.Field(i)
  114. if !fv.CanInterface() {
  115. continue
  116. }
  117. if ft.PkgPath != "" { // unexported
  118. continue
  119. }
  120. var name string
  121. var option string
  122. tag := ft.Tag.Get(tagName)
  123. if tag != "" {
  124. ts := strings.Split(tag, ",")
  125. if len(ts) == 1 {
  126. name = ts[0]
  127. } else if len(ts) > 1 {
  128. name = ts[0]
  129. option = ts[1]
  130. }
  131. if name == "-" {
  132. continue // skip this field
  133. }
  134. if name == "" {
  135. name = strings.ToLower(ft.Name)
  136. }
  137. if option == "omitempty" {
  138. if isEmpty(&fv) {
  139. continue // skip empty field
  140. }
  141. }
  142. } else {
  143. name = strings.ToLower(ft.Name)
  144. }
  145. if ft.Anonymous && fv.Kind() == reflect.Ptr && fv.IsNil() {
  146. continue
  147. }
  148. if (ft.Anonymous && fv.Kind() == reflect.Struct) ||
  149. (ft.Anonymous && fv.Kind() == reflect.Ptr && fv.Elem().Kind() == reflect.Struct) {
  150. // embedded struct
  151. embedded := Struct2MapByTag(fv.Interface(), tagName)
  152. for embName, embValue := range embedded {
  153. m[embName] = embValue
  154. }
  155. } else if option == "string" {
  156. kind := fv.Kind()
  157. if kind == reflect.Int || kind == reflect.Int8 || kind == reflect.Int16 || kind == reflect.Int32 || kind == reflect.Int64 {
  158. m[name] = strconv.FormatInt(fv.Int(), 10)
  159. } else if kind == reflect.Uint || kind == reflect.Uint8 || kind == reflect.Uint16 || kind == reflect.Uint32 || kind == reflect.Uint64 {
  160. m[name] = strconv.FormatUint(fv.Uint(), 10)
  161. } else if kind == reflect.Float32 || kind == reflect.Float64 {
  162. m[name] = strconv.FormatFloat(fv.Float(), 'f', 2, 64)
  163. } else {
  164. m[name] = fv.Interface()
  165. }
  166. } else {
  167. m[name] = fv.Interface()
  168. }
  169. }
  170. return m
  171. }
  172. func isEmpty(v *reflect.Value) bool {
  173. k := v.Kind()
  174. if k == reflect.Bool {
  175. return v.Bool() == false
  176. } else if reflect.Int < k && k < reflect.Int64 {
  177. return v.Int() == 0
  178. } else if reflect.Uint < k && k < reflect.Uintptr {
  179. return v.Uint() == 0
  180. } else if k == reflect.Float32 || k == reflect.Float64 {
  181. return v.Float() == 0
  182. } else if k == reflect.Array || k == reflect.Map || k == reflect.Slice || k == reflect.String {
  183. return v.Len() == 0
  184. } else if k == reflect.Interface || k == reflect.Ptr {
  185. return v.IsNil()
  186. }
  187. return false
  188. }
  189. func convertSlice(s string, name string, ft reflect.Type, fv reflect.Value) error {
  190. var err error
  191. et := ft.Elem()
  192. if et.Kind() == reflect.Ptr || et.Kind() == reflect.Struct {
  193. return convertJsonValue(s, name, fv)
  194. }
  195. ss := strings.Split(s, ",")
  196. if len(s) == 0 || len(ss) == 0 {
  197. return nil
  198. }
  199. fs := reflect.MakeSlice(ft, 0, len(ss))
  200. for _, si := range ss {
  201. ev := reflect.New(et).Elem()
  202. err = convertValue(et.Kind(), si, name, ev)
  203. if err != nil {
  204. return err
  205. }
  206. fs = reflect.Append(fs, ev)
  207. }
  208. fv.Set(fs)
  209. return nil
  210. }
  211. func convertJsonValue(s string, name string, fv reflect.Value) error {
  212. var err error
  213. d := StringToSlice(s)
  214. if fv.Kind() == reflect.Ptr {
  215. if fv.IsNil() {
  216. fv.Set(reflect.New(fv.Type().Elem()))
  217. }
  218. } else {
  219. fv = fv.Addr()
  220. }
  221. err = json.Unmarshal(d, fv.Interface())
  222. if err != nil {
  223. return fmt.Errorf("invalid json '%v': %v, %v", name, err.Error(), s)
  224. }
  225. return nil
  226. }
  227. func convertValue(kind reflect.Kind, s string, name string, fv reflect.Value) error {
  228. if !fv.CanAddr() {
  229. return fmt.Errorf("can not addr: %v", name)
  230. }
  231. if kind == reflect.String {
  232. fv.SetString(s)
  233. return nil
  234. }
  235. if kind == reflect.Bool {
  236. switch s {
  237. case "true":
  238. fv.SetBool(true)
  239. case "false":
  240. fv.SetBool(false)
  241. case "1":
  242. fv.SetBool(true)
  243. case "0":
  244. fv.SetBool(false)
  245. default:
  246. return fmt.Errorf("invalid bool: %v value=%v", name, s)
  247. }
  248. return nil
  249. }
  250. if reflect.Int <= kind && kind <= reflect.Int64 {
  251. i, err := strconv.ParseInt(s, 10, 64)
  252. if err != nil {
  253. return fmt.Errorf("invalid int: %v value=%v", name, s)
  254. }
  255. fv.SetInt(i)
  256. } else if reflect.Uint <= kind && kind <= reflect.Uint64 {
  257. i, err := strconv.ParseUint(s, 10, 64)
  258. if err != nil {
  259. return fmt.Errorf("invalid int: %v value=%v", name, s)
  260. }
  261. fv.SetUint(i)
  262. } else if reflect.Float32 == kind || kind == reflect.Float64 {
  263. i, err := strconv.ParseFloat(s, 64)
  264. if err != nil {
  265. return fmt.Errorf("invalid float: %v value=%v", name, s)
  266. }
  267. fv.SetFloat(i)
  268. } else {
  269. // not support or just ignore it?
  270. // return fmt.Errorf("type not support: field=%v(%v) value=%v(%v)", name, ft.Kind(), val, vt.Kind())
  271. }
  272. return nil
  273. }
  274. func parseTag(tag string) (string, string) {
  275. tags := strings.Split(tag, ",")
  276. if len(tags) <= 0 {
  277. return "", ""
  278. }
  279. if len(tags) == 1 {
  280. return tags[0], ""
  281. }
  282. return tags[0], tags[1]
  283. }