mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
optimized package gconv, supported struct attr with ptr
This commit is contained in:
@ -7,13 +7,13 @@
|
||||
package gconv
|
||||
|
||||
import (
|
||||
"gitee.com/johng/gf/g/container/gset"
|
||||
"gitee.com/johng/gf/g/util/gstr"
|
||||
"reflect"
|
||||
"gitee.com/johng/gf/third/github.com/fatih/structs"
|
||||
"strings"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gitee.com/johng/gf/g/container/gset"
|
||||
"gitee.com/johng/gf/g/util/gstr"
|
||||
"gitee.com/johng/gf/third/github.com/fatih/structs"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 将params键值对参数映射到对应的struct对象属性上,第三个参数mapping为非必需,表示自定义名称与属性名称的映射关系。
|
||||
@ -63,7 +63,7 @@ func Struct(params interface{}, objPointer interface{}, attrMapping...map[string
|
||||
for mappingk, mappingv := range attrMapping[0] {
|
||||
if v, ok := paramsMap[mappingk]; ok {
|
||||
dmap[mappingv] = true
|
||||
if err := bindVarToStruct(elem, mappingv, v); err != nil {
|
||||
if err := bindVarToStructAttr(elem, mappingv, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -78,7 +78,7 @@ func Struct(params interface{}, objPointer interface{}, attrMapping...map[string
|
||||
}
|
||||
if v, ok := paramsMap[tagk]; ok {
|
||||
dmap[tagv] = true
|
||||
if err := bindVarToStruct(elem, tagv, v); err != nil {
|
||||
if err := bindVarToStructAttr(elem, tagv, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -124,7 +124,7 @@ func Struct(params interface{}, objPointer interface{}, attrMapping...map[string
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
if err := bindVarToStruct(elem, name, mapv); err != nil {
|
||||
if err := bindVarToStructAttr(elem, name, mapv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -153,7 +153,7 @@ func getTagMapOfStruct(objPointer interface{}) map[string]string {
|
||||
}
|
||||
|
||||
// 将参数值绑定到对象指定名称的属性上
|
||||
func bindVarToStruct(elem reflect.Value, name string, value interface{}) (err error) {
|
||||
func bindVarToStructAttr(elem reflect.Value, name string, value interface{}) (err error) {
|
||||
structFieldValue := elem.FieldByName(name)
|
||||
// 键名与对象属性匹配检测,map中如果有struct不存在的属性,那么不做处理,直接return
|
||||
if !structFieldValue.IsValid() {
|
||||
@ -167,7 +167,7 @@ func bindVarToStruct(elem reflect.Value, name string, value interface{}) (err er
|
||||
defer func() {
|
||||
// 如果转换失败,那么可能是类型不匹配造成(例如属性包含自定义类型),那么执行递归转换
|
||||
if recover() != nil {
|
||||
err = bindVarToStructIfDefaultConvertionFailed(structFieldValue, value)
|
||||
err = bindVarToReflectValue(structFieldValue, value)
|
||||
}
|
||||
}()
|
||||
structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String())))
|
||||
@ -189,37 +189,62 @@ func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) (e
|
||||
defer func() {
|
||||
// 如果转换失败,那么可能是类型不匹配造成(例如属性包含自定义类型),那么执行递归转换
|
||||
if recover() != nil {
|
||||
err = bindVarToStructIfDefaultConvertionFailed(structFieldValue, value)
|
||||
err = bindVarToReflectValue(structFieldValue, value)
|
||||
}
|
||||
}()
|
||||
structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String())))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 当默认的基本类型转换失败时,通过recover判断后执行反射类型转换
|
||||
func bindVarToStructIfDefaultConvertionFailed(structFieldValue reflect.Value, value interface{}) error {
|
||||
// 当默认的基本类型转换失败时,通过recover判断后执行反射类型转换(处理复杂类型)
|
||||
func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}) error {
|
||||
switch structFieldValue.Kind() {
|
||||
// 属性为结构体
|
||||
case reflect.Struct:
|
||||
Struct(value, structFieldValue)
|
||||
|
||||
// 属性为数组类型
|
||||
case reflect.Slice: fallthrough
|
||||
case reflect.Array:
|
||||
a := reflect.Value{}
|
||||
v := reflect.ValueOf(value)
|
||||
if v.Kind() == reflect.Slice || v.Kind() == reflect.Array {
|
||||
a = reflect.MakeSlice(structFieldValue.Type(), v.Len(), v.Len())
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
n := reflect.New(structFieldValue.Type().Elem()).Elem()
|
||||
Struct(v.Index(i).Interface(), n)
|
||||
a.Index(i).Set(n)
|
||||
if v.Len() > 0 {
|
||||
a = reflect.MakeSlice(structFieldValue.Type(), v.Len(), v.Len())
|
||||
t := a.Index(0).Type()
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
e := reflect.New(t.Elem()).Elem()
|
||||
Struct(v.Index(i).Interface(), e)
|
||||
a.Index(i).Set(e.Addr())
|
||||
} else {
|
||||
e := reflect.New(t).Elem()
|
||||
Struct(v.Index(i).Interface(), e)
|
||||
a.Index(i).Set(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
a = reflect.MakeSlice(structFieldValue.Type(), 1, 1)
|
||||
n := reflect.New(structFieldValue.Type().Elem()).Elem()
|
||||
Struct(value, n)
|
||||
a.Index(0).Set(n)
|
||||
a = reflect.MakeSlice(structFieldValue.Type(), 1, 1)
|
||||
t := a.Index(0).Type()
|
||||
if t.Kind() == reflect.Ptr {
|
||||
e := reflect.New(t.Elem()).Elem()
|
||||
Struct(value, e)
|
||||
a.Index(0).Set(e.Addr())
|
||||
} else {
|
||||
e := reflect.New(t).Elem()
|
||||
Struct(value, e)
|
||||
a.Index(0).Set(e)
|
||||
}
|
||||
}
|
||||
structFieldValue.Set(a)
|
||||
|
||||
// 属性为指针类型
|
||||
case reflect.Ptr:
|
||||
e := reflect.New(structFieldValue.Type().Elem()).Elem()
|
||||
Struct(value, e)
|
||||
structFieldValue.Set(e.Addr())
|
||||
|
||||
default:
|
||||
return errors.New(fmt.Sprintf(`cannot convert to type "%s"`, structFieldValue.Type().String()))
|
||||
}
|
||||
|
||||
72
g/util/gconv/gconv_z_unit_struct_test.go
Normal file
72
g/util/gconv/gconv_z_unit_struct_test.go
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2018 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://gitee.com/johng/gf.
|
||||
|
||||
package gconv_test
|
||||
|
||||
import (
|
||||
"gitee.com/johng/gf/g"
|
||||
"gitee.com/johng/gf/g/util/gconv"
|
||||
"gitee.com/johng/gf/g/util/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
||||
func Test_Struct_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Uid int
|
||||
Name string
|
||||
Site_Url string
|
||||
NickName string
|
||||
Pass1 string `gconv:"password1"`
|
||||
Pass2 string `gconv:"password2"`
|
||||
}
|
||||
user := (*User)(nil)
|
||||
// 使用默认映射规则绑定属性值到对象
|
||||
user = new(User)
|
||||
params1 := g.Map{
|
||||
"uid" : 1,
|
||||
"Name" : "john",
|
||||
"siteurl" : "https://gfer.me",
|
||||
"nick_name" : "johng",
|
||||
"PASS1" : "123",
|
||||
"PASS2" : "456",
|
||||
}
|
||||
if err := gconv.Struct(params1, user); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
gtest.Assert(user, &User{
|
||||
Uid : 1,
|
||||
Name : "john",
|
||||
Site_Url : "https://gfer.me",
|
||||
NickName : "johng",
|
||||
Pass1 : "123",
|
||||
Pass2 : "456",
|
||||
})
|
||||
|
||||
// 使用struct tag映射绑定属性值到对象
|
||||
user = new(User)
|
||||
params2 := g.Map {
|
||||
"uid" : 2,
|
||||
"name" : "smith",
|
||||
"site-url" : "https://gfer.me",
|
||||
"nick name" : "johng",
|
||||
"password1" : "111",
|
||||
"password2" : "222",
|
||||
}
|
||||
if err := gconv.Struct(params2, user); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
gtest.Assert(user, &User{
|
||||
Uid : 2,
|
||||
Name : "smith",
|
||||
Site_Url : "https://gfer.me",
|
||||
NickName : "johng",
|
||||
Pass1 : "111",
|
||||
Pass2 : "222",
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -2,18 +2,31 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gitee.com/johng/gf/g"
|
||||
"gitee.com/johng/gf/g/util/gconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main(){
|
||||
type Test struct {
|
||||
Date time.Time `json:"date"`
|
||||
func main() {
|
||||
type Score struct {
|
||||
Name string
|
||||
Result int
|
||||
}
|
||||
o := new(Test)
|
||||
m := map[string]interface{}{
|
||||
"Date" : "",
|
||||
type User struct {
|
||||
Scores []*Score
|
||||
}
|
||||
gconv.Struct(m, o)
|
||||
fmt.Println(o)
|
||||
}
|
||||
|
||||
user := new(User)
|
||||
scores := map[string]interface{}{
|
||||
"Scores" : map[string]interface{}{
|
||||
"Name" : "john",
|
||||
"Result" : 100,
|
||||
},
|
||||
}
|
||||
|
||||
// 嵌套struct转换,属性为slice类型,数值为map类型
|
||||
if err := gconv.Struct(scores, user); err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
g.Dump(user)
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,7 @@ func main() {
|
||||
Result int
|
||||
}
|
||||
type User struct {
|
||||
Scores []Score
|
||||
Scores []*Score
|
||||
}
|
||||
|
||||
user := new(User)
|
||||
|
||||
Reference in New Issue
Block a user