mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
improve performance for gconv.Struct/Structs using directly reflect set
This commit is contained in:
@ -50,6 +50,11 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str
|
||||
if pointer == nil {
|
||||
return gerror.New("object pointer cannot be nil")
|
||||
}
|
||||
|
||||
if doStructByDirectReflectSet(params, pointer) {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Catch the panic, especially the reflect operation panics.
|
||||
if e := recover(); e != nil {
|
||||
@ -255,6 +260,20 @@ func doStruct(params interface{}, pointer interface{}, mapping ...map[string]str
|
||||
return nil
|
||||
}
|
||||
|
||||
// doStructByDirectReflectSet do the converting directly using reflect Set.
|
||||
// It returns true if success, or else false.
|
||||
func doStructByDirectReflectSet(params interface{}, pointer interface{}) (ok bool) {
|
||||
v1 := reflect.ValueOf(pointer)
|
||||
v2 := reflect.ValueOf(params)
|
||||
if v1.Kind() == reflect.Ptr {
|
||||
if elem := v1.Elem(); elem.IsValid() && elem.Type() == v2.Type() {
|
||||
elem.Set(v2)
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// bindVarToStructAttr sets value to struct object attribute by name.
|
||||
func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, mapping ...map[string]string) (err error) {
|
||||
structFieldValue := elem.FieldByName(name)
|
||||
|
||||
@ -38,6 +38,11 @@ func doStructs(params interface{}, pointer interface{}, mapping ...map[string]st
|
||||
if pointer == nil {
|
||||
return gerror.New("object pointer cannot be nil")
|
||||
}
|
||||
|
||||
if doStructsByDirectReflectSet(params, pointer) {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Catch the panic, especially the reflect operation panics.
|
||||
if e := recover(); e != nil {
|
||||
@ -104,5 +109,18 @@ func doStructs(params interface{}, pointer interface{}, mapping ...map[string]st
|
||||
}
|
||||
pointerRv.Elem().Set(array)
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// doStructsByDirectReflectSet do the converting directly using reflect Set.
|
||||
// It returns true if success, or else false.
|
||||
func doStructsByDirectReflectSet(params interface{}, pointer interface{}) (ok bool) {
|
||||
v1 := reflect.ValueOf(pointer)
|
||||
v2 := reflect.ValueOf(params)
|
||||
if v1.Kind() == reflect.Ptr {
|
||||
if elem := v1.Elem(); elem.IsValid() && elem.Type() == v2.Type() {
|
||||
elem.Set(v2)
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
package gconv
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -22,7 +23,27 @@ var (
|
||||
"name": "gf",
|
||||
"score": 100,
|
||||
}
|
||||
structPointer = new(structType)
|
||||
structObj = structType{
|
||||
Name: "john",
|
||||
Score: 60,
|
||||
}
|
||||
structPointer = &structType{
|
||||
Name: "john",
|
||||
Score: 60,
|
||||
}
|
||||
structPointerNil *structType
|
||||
// struct slice
|
||||
structSliceNil []structType
|
||||
structSlice = []structType{
|
||||
{Name: "john", Score: 60},
|
||||
{Name: "smith", Score: 100},
|
||||
}
|
||||
// struct pointer slice
|
||||
structPointerSliceNil []*structType
|
||||
structPointerSlice = []*structType{
|
||||
{Name: "john", Score: 60},
|
||||
{Name: "smith", Score: 100},
|
||||
}
|
||||
)
|
||||
|
||||
func Benchmark_Struct_Basic(b *testing.B) {
|
||||
@ -30,3 +51,83 @@ func Benchmark_Struct_Basic(b *testing.B) {
|
||||
Struct(structMap, structPointer)
|
||||
}
|
||||
}
|
||||
|
||||
// *struct -> **struct
|
||||
func Benchmark_Reflect_PPStruct_PStruct(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
v1 := reflect.ValueOf(&structPointerNil)
|
||||
v2 := reflect.ValueOf(structPointer)
|
||||
//if v1.Kind() == reflect.Ptr {
|
||||
// if elem := v1.Elem(); elem.Type() == v2.Type() {
|
||||
// elem.Set(v2)
|
||||
// }
|
||||
//}
|
||||
v1.Elem().Set(v2)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Struct_PPStruct_PStruct(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Struct(structPointer, &structPointerNil)
|
||||
}
|
||||
}
|
||||
|
||||
// struct -> *struct
|
||||
func Benchmark_Reflect_PStruct_Struct(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
v1 := reflect.ValueOf(structPointer)
|
||||
v2 := reflect.ValueOf(structObj)
|
||||
//if v1.Kind() == reflect.Ptr {
|
||||
// if elem := v1.Elem(); elem.Type() == v2.Type() {
|
||||
// elem.Set(v2)
|
||||
// }
|
||||
//}
|
||||
v1.Elem().Set(v2)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Struct_PStruct_Struct(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Struct(structObj, structPointer)
|
||||
}
|
||||
}
|
||||
|
||||
// []struct -> *[]struct
|
||||
func Benchmark_Reflect_PStructs_Structs(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
v1 := reflect.ValueOf(&structSliceNil)
|
||||
v2 := reflect.ValueOf(structSlice)
|
||||
//if v1.Kind() == reflect.Ptr {
|
||||
// if elem := v1.Elem(); elem.Type() == v2.Type() {
|
||||
// elem.Set(v2)
|
||||
// }
|
||||
//}
|
||||
v1.Elem().Set(v2)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Structs_PStructs_Structs(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Structs(structSlice, &structSliceNil)
|
||||
}
|
||||
}
|
||||
|
||||
// []*struct -> *[]*struct
|
||||
func Benchmark_Reflect_PPStructs_PStructs(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
v1 := reflect.ValueOf(&structPointerSliceNil)
|
||||
v2 := reflect.ValueOf(structPointerSlice)
|
||||
//if v1.Kind() == reflect.Ptr {
|
||||
// if elem := v1.Elem(); elem.Type() == v2.Type() {
|
||||
// elem.Set(v2)
|
||||
// }
|
||||
//}
|
||||
v1.Elem().Set(v2)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Structs_PPStructs_PStructs(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Structs(structPointerSlice, &structPointerSliceNil)
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,3 +143,34 @@ func Test_Struct_SliceWithTag(t *testing.T) {
|
||||
t.Assert(users[1].NickName, "name2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Structs_DirectReflectSet(t *testing.T) {
|
||||
type A struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
a = []*A{
|
||||
{Id: 1, Name: "john"},
|
||||
{Id: 2, Name: "smith"},
|
||||
}
|
||||
b []*A
|
||||
)
|
||||
err := gconv.Structs(a, &b)
|
||||
t.Assert(err, nil)
|
||||
t.AssertEQ(a, b)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
a = []A{
|
||||
{Id: 1, Name: "john"},
|
||||
{Id: 2, Name: "smith"},
|
||||
}
|
||||
b []A
|
||||
)
|
||||
err := gconv.Structs(a, &b)
|
||||
t.Assert(err, nil)
|
||||
t.AssertEQ(a, b)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1003,3 +1003,35 @@ func Test_Struct_AttrStructHasTheSameTag(t *testing.T) {
|
||||
t.Assert(order.Product.UpdatedAtFormat, "")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Struct_DirectReflectSet(t *testing.T) {
|
||||
type A struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
a = &A{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
}
|
||||
b *A
|
||||
)
|
||||
err := gconv.Struct(a, &b)
|
||||
t.Assert(err, nil)
|
||||
t.AssertEQ(a, b)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
a = A{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
}
|
||||
b A
|
||||
)
|
||||
err := gconv.Struct(a, &b)
|
||||
t.Assert(err, nil)
|
||||
t.AssertEQ(a, b)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user