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  }