mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
inprove gconv.Interfaces for struct type
This commit is contained in:
@ -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
|
||||
}
|
||||
|
||||
@ -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}
|
||||
}
|
||||
|
||||
@ -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}})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -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})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user