From 25a91c732c9cbc59d3e5118c38011637f4a16855 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 7 Apr 2020 21:29:41 +0800 Subject: [PATCH] improve String/Map converting for package gconv --- util/gconv/gconv.go | 50 +++--- util/gconv/gconv_map.go | 330 ++++++++++++++++++++-------------------- 2 files changed, 190 insertions(+), 190 deletions(-) diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index e4449d49e..594d21b39 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -231,35 +231,35 @@ func String(i interface{}) string { // If the variable implements the String() interface, // then use that interface to perform the conversion return f.String() - } else if f, ok := value.(apiError); ok { + } + if f, ok := value.(apiError); ok { // If the variable implements the Error() interface, // then use that interface to perform the conversion return f.Error() + } + // Reflect checks. + rv := reflect.ValueOf(value) + kind := rv.Kind() + switch kind { + case reflect.Chan, + reflect.Map, + reflect.Slice, + reflect.Func, + reflect.Ptr, + reflect.Interface, + reflect.UnsafePointer: + if rv.IsNil() { + return "" + } + } + if kind == reflect.Ptr { + return String(rv.Elem().Interface()) + } + // Finally we use json.Marshal to convert. + if jsonContent, err := json.Marshal(value); err != nil { + return fmt.Sprint(value) } else { - // Reflect checks. - rv := reflect.ValueOf(value) - kind := rv.Kind() - switch kind { - case reflect.Chan, - reflect.Map, - reflect.Slice, - reflect.Func, - reflect.Ptr, - reflect.Interface, - reflect.UnsafePointer: - if rv.IsNil() { - return "" - } - } - if kind == reflect.Ptr { - return String(rv.Elem().Interface()) - } - // Finally we use json.Marshal to convert. - if jsonContent, err := json.Marshal(value); err != nil { - return fmt.Sprint(value) - } else { - return string(jsonContent) - } + return string(jsonContent) } } } diff --git a/util/gconv/gconv_map.go b/util/gconv/gconv_map.go index 8631a7d72..695f9ac54 100644 --- a/util/gconv/gconv_map.go +++ b/util/gconv/gconv_map.go @@ -45,192 +45,192 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string] if value == nil { return nil } - if r, ok := value.(map[string]interface{}); ok { + + // Assert the common combination of types, and finally it uses reflection. + m := make(map[string]interface{}) + switch r := value.(type) { + case string: + if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { + if err := json.Unmarshal([]byte(r), &m); err != nil { + return nil + } + } else { + return nil + } + case []byte: + if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { + if err := json.Unmarshal(r, &m); err != nil { + return nil + } + } else { + return nil + } + case map[interface{}]interface{}: + for k, v := range r { + m[String(k)] = v + } + case map[interface{}]string: + for k, v := range r { + m[String(k)] = v + } + case map[interface{}]int: + for k, v := range r { + m[String(k)] = v + } + case map[interface{}]uint: + for k, v := range r { + m[String(k)] = v + } + case map[interface{}]float32: + for k, v := range r { + m[String(k)] = v + } + case map[interface{}]float64: + for k, v := range r { + m[String(k)] = v + } + case map[string]bool: + for k, v := range r { + m[k] = v + } + case map[string]int: + for k, v := range r { + m[k] = v + } + case map[string]uint: + for k, v := range r { + m[k] = v + } + case map[string]float32: + for k, v := range r { + m[k] = v + } + case map[string]float64: + for k, v := range r { + m[k] = v + } + case map[string]interface{}: return r - } else { - // Assert the common combination of types, and finally it uses reflection. - m := make(map[string]interface{}) - switch r := value.(type) { - case string: - if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { - if err := json.Unmarshal([]byte(r), &m); err != nil { - return nil + case map[int]interface{}: + for k, v := range r { + m[String(k)] = v + } + case map[int]string: + for k, v := range r { + m[String(k)] = v + } + case map[uint]string: + for k, v := range r { + m[String(k)] = v + } + // Not a common type, it then uses reflection for conversion. + default: + rv := reflect.ValueOf(value) + kind := rv.Kind() + // If it is a pointer, we should find its real data type. + if kind == reflect.Ptr { + rv = rv.Elem() + kind = rv.Kind() + } + switch kind { + // If is type of array, it converts the value of even number index as its key and + // the value of odd number index as its corresponding value. + // Eg: + // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"} + // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil} + case reflect.Slice, reflect.Array: + length := rv.Len() + for i := 0; i < length; i += 2 { + if i+1 < length { + m[String(rv.Index(i).Interface())] = rv.Index(i + 1).Interface() + } else { + m[String(rv.Index(i).Interface())] = nil } - } else { - return nil } - case []byte: - if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { - if err := json.Unmarshal(r, &m); err != nil { - return nil + case reflect.Map: + ks := rv.MapKeys() + for _, k := range ks { + m[String(k.Interface())] = rv.MapIndex(k).Interface() + } + case reflect.Struct: + // Map converting interface check. + if v, ok := value.(apiMapStrAny); ok { + return v.MapStrAny() + } + // Using reflect for converting. + rt := rv.Type() + name := "" + tagArray := structTagPriority + switch len(tags) { + case 0: + // No need handle. + case 1: + tagArray = append(strings.Split(tags[0], ","), structTagPriority...) + default: + tagArray = append(tags, structTagPriority...) + } + var rtField reflect.StructField + var rvField reflect.Value + var rvKind reflect.Kind + for i := 0; i < rv.NumField(); i++ { + rtField = rt.Field(i) + rvField = rv.Field(i) + // Only convert the public attributes. + fieldName := rtField.Name + if !utils.IsLetterUpper(fieldName[0]) { + continue } - } else { - return nil - } - case map[interface{}]interface{}: - for k, v := range r { - m[String(k)] = v - } - case map[interface{}]string: - for k, v := range r { - m[String(k)] = v - } - case map[interface{}]int: - for k, v := range r { - m[String(k)] = v - } - case map[interface{}]uint: - for k, v := range r { - m[String(k)] = v - } - case map[interface{}]float32: - for k, v := range r { - m[String(k)] = v - } - case map[interface{}]float64: - for k, v := range r { - m[String(k)] = v - } - case map[string]bool: - for k, v := range r { - m[k] = v - } - case map[string]int: - for k, v := range r { - m[k] = v - } - case map[string]uint: - for k, v := range r { - m[k] = v - } - case map[string]float32: - for k, v := range r { - m[k] = v - } - case map[string]float64: - for k, v := range r { - m[k] = v - } - case map[int]interface{}: - for k, v := range r { - m[String(k)] = v - } - case map[int]string: - for k, v := range r { - m[String(k)] = v - } - case map[uint]string: - for k, v := range r { - m[String(k)] = v - } - // Not a common type, it then uses reflection for conversion. - default: - rv := reflect.ValueOf(value) - kind := rv.Kind() - // If it is a pointer, we should find its real data type. - if kind == reflect.Ptr { - rv = rv.Elem() - kind = rv.Kind() - } - switch kind { - // If is type of array, it converts the value of even number index as its key and - // the value of odd number index as its corresponding value. - // Eg: - // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"} - // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil} - case reflect.Slice, reflect.Array: - length := rv.Len() - for i := 0; i < length; i += 2 { - if i+1 < length { - m[String(rv.Index(i).Interface())] = rv.Index(i + 1).Interface() - } else { - m[String(rv.Index(i).Interface())] = nil + name = "" + fieldTag := rtField.Tag + for _, tag := range tagArray { + if name = fieldTag.Get(tag); name != "" { + break } } - case reflect.Map: - ks := rv.MapKeys() - for _, k := range ks { - m[String(k.Interface())] = rv.MapIndex(k).Interface() - } - case reflect.Struct: - // Map converting interface check. - if v, ok := value.(apiMapStrAny); ok { - return v.MapStrAny() - } - rt := rv.Type() - name := "" - tagArray := structTagPriority - switch len(tags) { - case 0: - // No need handle. - case 1: - tagArray = append(strings.Split(tags[0], ","), structTagPriority...) - default: - tagArray = append(tags, structTagPriority...) - } - var rtField reflect.StructField - var rvField reflect.Value - var rvKind reflect.Kind - for i := 0; i < rv.NumField(); i++ { - rtField = rt.Field(i) - rvField = rv.Field(i) - // Only convert the public attributes. - fieldName := rtField.Name - if !utils.IsLetterUpper(fieldName[0]) { + if name == "" { + name = strings.TrimSpace(fieldName) + } else { + // Support json tag feature: -, omitempty + name = strings.TrimSpace(name) + if name == "-" { continue } - name = "" - fieldTag := rtField.Tag - for _, tag := range tagArray { - if name = fieldTag.Get(tag); name != "" { - break - } - } - if name == "" { - name = strings.TrimSpace(fieldName) - } else { - // Support json tag feature: -, omitempty - name = strings.TrimSpace(name) - if name == "-" { - continue - } - array := strings.Split(name, ",") - if len(array) > 1 { - switch strings.TrimSpace(array[1]) { - case "omitempty": - if empty.IsEmpty(rvField.Interface()) { - continue - } else { - name = strings.TrimSpace(array[0]) - } - default: + array := strings.Split(name, ",") + if len(array) > 1 { + switch strings.TrimSpace(array[1]) { + case "omitempty": + if empty.IsEmpty(rvField.Interface()) { + continue + } else { name = strings.TrimSpace(array[0]) } + default: + name = strings.TrimSpace(array[0]) } } - if recursive { + } + if recursive { + rvKind = rvField.Kind() + if rvKind == reflect.Ptr { + rvField = rvField.Elem() rvKind = rvField.Kind() - if rvKind == reflect.Ptr { - rvField = rvField.Elem() - rvKind = rvField.Kind() - } - if rvKind == reflect.Struct { - for k, v := range doMapConvert(rvField.Interface(), recursive, tags...) { - m[k] = v - } - } else { - m[name] = rvField.Interface() + } + if rvKind == reflect.Struct { + for k, v := range doMapConvert(rvField.Interface(), recursive, tags...) { + m[k] = v } } else { m[name] = rvField.Interface() } + } else { + m[name] = rvField.Interface() } - default: - return nil } + default: + return nil } - return m } + return m } // MapStrStr converts to map[string]string.