mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
improve converting performance for equal type converting
This commit is contained in:
19
container/gvar/gvar_scan.go
Normal file
19
container/gvar/gvar_scan.go
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). 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://github.com/gogf/gf.
|
||||
|
||||
package gvar
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
// Scan automatically checks the type of `pointer` and converts `params` to `pointer`. It supports `pointer`
|
||||
// with type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` for converting.
|
||||
//
|
||||
// See gconv.Scan.
|
||||
func (v *Var) Scan(pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.Scan(v.Val(), pointer, mapping...)
|
||||
}
|
||||
@ -21,12 +21,3 @@ func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error {
|
||||
func (v *Var) Structs(pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.Structs(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
// Scan automatically calls Struct or Structs function according to the type of parameter
|
||||
// `pointer` to implement the converting.
|
||||
//
|
||||
// It calls function Struct if `pointer` is type of *struct/**struct to do the converting.
|
||||
// It calls function Structs if `pointer` is type of *[]struct/*[]*struct to do the converting.
|
||||
func (v *Var) Scan(pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.Scan(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
@ -21,14 +21,18 @@ import (
|
||||
// It calls function `doStructs` internally if `pointer` is type of *[]struct/*[]*struct for converting.
|
||||
func Scan(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
var (
|
||||
pointerType reflect.Type
|
||||
pointerKind reflect.Kind
|
||||
pointerType reflect.Type
|
||||
pointerKind reflect.Kind
|
||||
pointerValue reflect.Value
|
||||
)
|
||||
if v, ok := pointer.(reflect.Value); ok {
|
||||
pointerValue = v
|
||||
pointerType = v.Type()
|
||||
} else {
|
||||
pointerType = reflect.TypeOf(pointer)
|
||||
pointerValue = reflect.ValueOf(pointer)
|
||||
pointerType = reflect.TypeOf(pointer) // Do not use pointerValue.Type() as pointerValue might be zero.
|
||||
}
|
||||
|
||||
if pointerType == nil {
|
||||
return gerror.NewCode(gcode.CodeInvalidParameter, "parameter pointer should not be nil")
|
||||
}
|
||||
@ -36,6 +40,30 @@ func Scan(params interface{}, pointer interface{}, mapping ...map[string]string)
|
||||
if pointerKind != reflect.Ptr {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "params should be type of pointer, but got type: %v", pointerKind)
|
||||
}
|
||||
|
||||
// Direct assignment checks!
|
||||
var (
|
||||
paramsType reflect.Type
|
||||
paramsValue reflect.Value
|
||||
)
|
||||
if v, ok := params.(reflect.Value); ok {
|
||||
paramsValue = v
|
||||
paramsType = paramsValue.Type()
|
||||
} else {
|
||||
paramsValue = reflect.ValueOf(params)
|
||||
paramsType = reflect.TypeOf(params) // Do not use paramsValue.Type() as paramsValue might be zero.
|
||||
}
|
||||
// If `params` and `pointer` are the same type, the do directly assignment.
|
||||
// For performance enhancement purpose.
|
||||
var (
|
||||
pointerValueElem = pointerValue.Elem()
|
||||
)
|
||||
if pointerValueElem.CanSet() && paramsType == pointerValueElem.Type() {
|
||||
pointerValueElem.Set(paramsValue)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Converting.
|
||||
var (
|
||||
pointerElem = pointerType.Elem()
|
||||
pointerElemKind = pointerElem.Kind()
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
package gconv_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
@ -275,3 +276,46 @@ func Test_Scan_JsonAttributes_StringArray(t *testing.T) {
|
||||
t.Assert(len(s.Array), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Scan_SameType_Just_Assign(t *testing.T) {
|
||||
// Struct.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
Uid int
|
||||
Name string
|
||||
Pass1 string
|
||||
Pass2 string
|
||||
Pointer *int
|
||||
}
|
||||
var (
|
||||
int1 = 1
|
||||
int2 = 1
|
||||
user1 = new(User)
|
||||
user2 *User
|
||||
)
|
||||
user1.Pointer = &int1
|
||||
err := gconv.Scan(user1, &user2)
|
||||
t.AssertNil(err)
|
||||
t.Assert(fmt.Sprintf(`%p`, user1), fmt.Sprintf(`%p`, user2))
|
||||
t.Assert(*user1.Pointer, *user2.Pointer)
|
||||
user1.Pointer = &int2
|
||||
t.Assert(*user1.Pointer, *user2.Pointer)
|
||||
})
|
||||
// Map.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
int1 = 1
|
||||
int2 = 1
|
||||
m1 = map[string]*int{
|
||||
"int": &int1,
|
||||
}
|
||||
m2 map[string]*int
|
||||
)
|
||||
err := gconv.Scan(m1, &m2)
|
||||
t.AssertNil(err)
|
||||
t.Assert(fmt.Sprintf(`%p`, m1), fmt.Sprintf(`%p`, m2))
|
||||
t.Assert(*m1["int"], *m2["int"])
|
||||
m1["int"] = &int2
|
||||
t.Assert(*m1["int"], *m2["int"])
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user