From c56f4eabca27e90865cb173337fe2f2bf6953aa2 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 29 Nov 2020 21:34:28 +0800 Subject: [PATCH] inprove gconv.Interfaces for struct type --- util/gconv/gconv_map.go | 68 +++++++++++++-------------- util/gconv/gconv_slice_any.go | 37 +++++++-------- util/gconv/gconv_z_unit_all_test.go | 8 ++-- util/gconv/gconv_z_unit_slice_test.go | 7 ++- 4 files changed, 59 insertions(+), 61 deletions(-) diff --git a/util/gconv/gconv_map.go b/util/gconv/gconv_map.go index 8c31806dc..d3e62fda0 100644 --- a/util/gconv/gconv_map.go +++ b/util/gconv/gconv_map.go @@ -141,30 +141,30 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string] default: // Not a common type, it then uses reflection for conversion. - var rv reflect.Value + var reflectValue reflect.Value if v, ok := value.(reflect.Value); ok { - rv = v + reflectValue = v } else { - rv = reflect.ValueOf(value) + reflectValue = reflect.ValueOf(value) } - kind := rv.Kind() + reflectKind := reflectValue.Kind() // If it is a pointer, we should find its real data type. - if kind == reflect.Ptr { - rv = rv.Elem() - kind = rv.Kind() + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() } - switch kind { + switch reflectKind { // 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, for example: // []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() + length := reflectValue.Len() for i := 0; i < length; i += 2 { if i+1 < length { - dataMap[String(rv.Index(i).Interface())] = rv.Index(i + 1).Interface() + dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() } else { - dataMap[String(rv.Index(i).Interface())] = nil + dataMap[String(reflectValue.Index(i).Interface())] = nil } } case reflect.Map, reflect.Struct: @@ -184,29 +184,29 @@ func doMapConvertForMapOrStructValue(isRoot bool, value interface{}, recursive b if isRoot == false && recursive == false { return value } - var rv reflect.Value + var reflectValue reflect.Value if v, ok := value.(reflect.Value); ok { - rv = v + reflectValue = v value = v.Interface() } else { - rv = reflect.ValueOf(value) + reflectValue = reflect.ValueOf(value) } - kind := rv.Kind() + reflectKind := reflectValue.Kind() // If it is a pointer, we should find its real data type. - for kind == reflect.Ptr { - rv = rv.Elem() - kind = rv.Kind() + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() } - switch kind { + switch reflectKind { case reflect.Map: var ( - mapKeys = rv.MapKeys() + mapKeys = reflectValue.MapKeys() dataMap = make(map[string]interface{}) ) for _, k := range mapKeys { dataMap[String(k.Interface())] = doMapConvertForMapOrStructValue( false, - rv.MapIndex(k).Interface(), + reflectValue.MapIndex(k).Interface(), recursive, tags..., ) @@ -228,15 +228,15 @@ func doMapConvertForMapOrStructValue(isRoot bool, value interface{}, recursive b } // Using reflect for converting. var ( - rtField reflect.StructField - rvField reflect.Value - dataMap = make(map[string]interface{}) // result map. - rt = rv.Type() // attribute value type. - name = "" // name may be the tag name or the struct attribute name. + rtField reflect.StructField + rvField reflect.Value + dataMap = make(map[string]interface{}) // result map. + reflectType = reflectValue.Type() // attribute value type. + name = "" // name may be the tag name or the struct attribute name. ) - for i := 0; i < rv.NumField(); i++ { - rtField = rt.Field(i) - rvField = rv.Field(i) + for i := 0; i < reflectValue.NumField(); i++ { + rtField = reflectType.Field(i) + rvField = reflectValue.Field(i) // Only convert the public attributes. fieldName := rtField.Name if !utils.IsLetterUpper(fieldName[0]) { @@ -320,7 +320,7 @@ func doMapConvertForMapOrStructValue(isRoot bool, value interface{}, recursive b default: if rvField.IsValid() { - dataMap[name] = rv.Field(i).Interface() + dataMap[name] = reflectValue.Field(i).Interface() } else { dataMap[name] = nil } @@ -328,7 +328,7 @@ func doMapConvertForMapOrStructValue(isRoot bool, value interface{}, recursive b } else { // No recursive map value converting if rvField.IsValid() { - dataMap[name] = rv.Field(i).Interface() + dataMap[name] = reflectValue.Field(i).Interface() } else { dataMap[name] = nil } @@ -341,13 +341,13 @@ func doMapConvertForMapOrStructValue(isRoot bool, value interface{}, recursive b // The given value is type of slice. case reflect.Array, reflect.Slice: - length := rv.Len() + length := reflectValue.Len() if length == 0 { break } - array := make([]interface{}, rv.Len()) + array := make([]interface{}, reflectValue.Len()) for i := 0; i < length; i++ { - array[i] = doMapConvertForMapOrStructValue(false, rv.Index(i), recursive, tags...) + array[i] = doMapConvertForMapOrStructValue(false, reflectValue.Index(i), recursive, tags...) } return array } diff --git a/util/gconv/gconv_slice_any.go b/util/gconv/gconv_slice_any.go index f959c7760..7a7ce51a7 100644 --- a/util/gconv/gconv_slice_any.go +++ b/util/gconv/gconv_slice_any.go @@ -99,29 +99,28 @@ func Interfaces(i interface{}) []interface{} { default: // Finally we use reflection. var ( - rv = reflect.ValueOf(i) - kind = rv.Kind() + reflectValue = reflect.ValueOf(i) + reflectKind = reflectValue.Kind() ) - for kind == reflect.Ptr { - rv = rv.Elem() - kind = rv.Kind() + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() } - switch kind { + switch reflectKind { case reflect.Slice, reflect.Array: - array = make([]interface{}, rv.Len()) - for i := 0; i < rv.Len(); i++ { - array[i] = rv.Index(i).Interface() + array = make([]interface{}, reflectValue.Len()) + for i := 0; i < reflectValue.Len(); i++ { + array[i] = reflectValue.Index(i).Interface() + } + // Eg: {"K1": "v1", "K2": "v2"} => ["K1", "v1", "K2", "v2"] + case reflect.Struct: + array = make([]interface{}, 0) + // Note that, it uses the gconv tag name instead of the attribute name if + // the gconv tag is fined in the struct attributes. + for k, v := range Map(reflectValue) { + array = append(array, k) + array = append(array, v) } - //case reflect.Struct: - // rt := rv.Type() - // array = make([]interface{}, 0) - // for i := 0; i < rv.NumField(); i++ { - // // Only public attributes. - // if !utils.IsLetterUpper(rt.Field(i).Name[0]) { - // continue - // } - // array = append(array, rv.Field(i).Interface()) - // } default: return []interface{}{i} } diff --git a/util/gconv/gconv_z_unit_all_test.go b/util/gconv/gconv_z_unit_all_test.go index e250a263e..088c30d23 100644 --- a/util/gconv/gconv_z_unit_all_test.go +++ b/util/gconv/gconv_z_unit_all_test.go @@ -747,14 +747,14 @@ func Test_Slice_All(t *testing.T) { // 私有属性不会进行转换 func Test_Slice_PrivateAttribute_All(t *testing.T) { type User struct { - Id int - name string - Ad []interface{} + Id int `json:"id"` + name string `json:"name"` + Ad []interface{} `json:"ad"` } gtest.C(t, func(t *gtest.T) { user := &User{1, "john", []interface{}{2}} //t.Assert(gconv.Interfaces(user), g.Slice{1, []interface{}{2}}) - t.Assert(gconv.Interfaces(user), g.Slice{user}) + t.Assert(gconv.Interfaces(user), g.Slice{"id", 1, "ad", g.Slice{2}}) }) } diff --git a/util/gconv/gconv_z_unit_slice_test.go b/util/gconv/gconv_z_unit_slice_test.go index 2642b5338..880fb6346 100644 --- a/util/gconv/gconv_z_unit_slice_test.go +++ b/util/gconv/gconv_z_unit_slice_test.go @@ -38,13 +38,12 @@ func Test_Strings(t *testing.T) { func Test_Slice_PrivateAttribute(t *testing.T) { type User struct { - Id int - name string + Id int `json:"id"` + name string `json:"name"` } gtest.C(t, func(t *gtest.T) { user := &User{1, "john"} - //t.Assert(gconv.Interfaces(user), g.Slice{1}) - t.Assert(gconv.Interfaces(user), g.Slice{user}) + t.Assert(gconv.Interfaces(user), g.Slice{"id", 1}) }) }