inprove gconv.Interfaces for struct type

This commit is contained in:
John
2020-11-29 21:34:28 +08:00
parent bfe89e0b12
commit c56f4eabca
4 changed files with 59 additions and 61 deletions

View File

@ -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 <value> 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
}

View File

@ -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}
}

View File

@ -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}})
})
}

View File

@ -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})
})
}