diff --git a/g/container/gtype/gtype_test.go b/g/container/gtype/gtype_test.go index 736d064e5..5785b9af0 100644 --- a/g/container/gtype/gtype_test.go +++ b/g/container/gtype/gtype_test.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://gitee.com/johng/gf. -// go test *.go -bench=".*" +// go test *.go -bench=".*" -benchmem package gtype diff --git a/g/container/gvar/gvar_bench_test.go b/g/container/gvar/gvar_bench_test.go new file mode 100644 index 000000000..160bbd9ce --- /dev/null +++ b/g/container/gvar/gvar_bench_test.go @@ -0,0 +1,145 @@ +// 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. + +// go test *.go -bench=".*" -benchmem + +package gvar + +import "testing" + +var vn = New(nil) + +func Benchmark_Set(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Set(i) + } +} + +func Benchmark_Val(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Val() + } +} + +func Benchmark_IsNil(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.IsNil() + } +} + +func Benchmark_Bytes(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Bytes() + } +} + +func Benchmark_String(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.String() + } +} + +func Benchmark_Bool(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Bool() + } +} + +func Benchmark_Int(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Int() + } +} + +func Benchmark_Int8(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Int8() + } +} + +func Benchmark_Int16(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Int16() + } +} + +func Benchmark_Int32(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Int32() + } +} + +func Benchmark_Int64(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Int64() + } +} + +func Benchmark_Uint(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Uint() + } +} + +func Benchmark_Uint8(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Uint8() + } +} + +func Benchmark_Uint16(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Uint16() + } +} + +func Benchmark_Uint32(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Uint32() + } +} + +func Benchmark_Uint64(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Uint64() + } +} + +func Benchmark_Float32(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Float32() + } +} + +func Benchmark_Float64(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Float64() + } +} + +func Benchmark_Ints(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Ints() + } +} + +func Benchmark_Strings(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Strings() + } +} + +func Benchmark_Floats(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Floats() + } +} + +func Benchmark_Interfaces(b *testing.B) { + for i := 0; i < b.N; i++ { + vn.Interfaces() + } +} diff --git a/g/database/gdb/gdb.go b/g/database/gdb/gdb.go index aaeb3ce71..42080302b 100644 --- a/g/database/gdb/gdb.go +++ b/g/database/gdb/gdb.go @@ -19,6 +19,7 @@ import ( "gitee.com/johng/gf/g/os/gcache" "gitee.com/johng/gf/g/util/grand" _ "github.com/go-sql-driver/mysql" + "gitee.com/johng/gf/g/container/gvar" ) const ( @@ -108,7 +109,7 @@ type Sql struct { } // 返回数据表记录值 -type Value []byte +type Value = *gvar.Var // 返回数据表记录Map type Record map[string]Value diff --git a/g/database/gdb/gdb_base.go b/g/database/gdb/gdb_base.go index 811ed1ec4..48df5d1e1 100644 --- a/g/database/gdb/gdb_base.go +++ b/g/database/gdb/gdb_base.go @@ -19,6 +19,7 @@ import ( "gitee.com/johng/gf/g/os/gtime" "time" "gitee.com/johng/gf/g/os/glog" + "gitee.com/johng/gf/g/container/gvar" ) const ( @@ -195,10 +196,9 @@ func (db *Db) GetAll(query string, args ...interface{}) (Result, error) { row := make(Record) // 注意col字段是一个[]byte类型(slice类型本身是一个指针),多个记录循环时该变量指向的是同一个内存地址 for i, col := range values { - k := columns[i] v := make([]byte, len(col)) copy(v, col) - row[k] = v + row[columns[i]] = gvar.New(v) } records = append(records, row) } diff --git a/g/database/gdb/gdb_transaction.go b/g/database/gdb/gdb_transaction.go index e911ce684..6d8281899 100644 --- a/g/database/gdb/gdb_transaction.go +++ b/g/database/gdb/gdb_transaction.go @@ -15,6 +15,7 @@ import ( "gitee.com/johng/gf/g/os/gtime" "gitee.com/johng/gf/g/util/gconv" _ "github.com/go-sql-driver/mysql" + "gitee.com/johng/gf/g/container/gvar" ) // 数据库事务对象 @@ -115,10 +116,9 @@ func (tx *Tx) GetAll(query string, args ...interface{}) (Result, error) { row := make(Record) // 注意col字段是一个[]byte类型(slice类型本身是一个指针),多个记录循环时该变量指向的是同一个内存地址 for i, col := range values { - k := columns[i] v := make([]byte, len(col)) copy(v, col) - row[k] = v + row[columns[i]] = gvar.New(v) } //fmt.Printf("%p\n", row["typeid"]) records = append(records, row) diff --git a/g/database/gdb/gdb_type_value.go b/g/database/gdb/gdb_type_value.go deleted file mode 100644 index 226701b44..000000000 --- a/g/database/gdb/gdb_type_value.go +++ /dev/null @@ -1,35 +0,0 @@ -// 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 gdb - -import ( - "time" - "gitee.com/johng/gf/g/util/gconv" -) - -func (v Value) IsNil() bool { return v == nil } -func (v Value) Bytes() []byte { return []byte(v) } -func (v Value) String() string { return string(v.Bytes()) } -func (v Value) Bool() bool { return gconv.Bool(v.Bytes()) } - -func (v Value) Int() int { return gconv.Int(v.Bytes()) } -func (v Value) Int8() int8 { return gconv.Int8(v.Bytes()) } -func (v Value) Int16() int16 { return gconv.Int16(v.Bytes()) } -func (v Value) Int32() int32 { return gconv.Int32(v.Bytes()) } -func (v Value) Int64() int64 { return gconv.Int64(v.Bytes()) } - -func (v Value) Uint() uint { return gconv.Uint(v.Bytes()) } -func (v Value) Uint8() uint8 { return gconv.Uint8(v.Bytes()) } -func (v Value) Uint16() uint16 { return gconv.Uint16(v.Bytes()) } -func (v Value) Uint32() uint32 { return gconv.Uint32(v.Bytes()) } -func (v Value) Uint64() uint64 { return gconv.Uint64(v.Bytes()) } - -func (v Value) Float32() float32 { return gconv.Float32(v.Bytes()) } -func (v Value) Float64() float64 { return gconv.Float64(v.Bytes()) } - -func (v Value) Time(format...string) time.Time { return gconv.Time(v.Bytes(), format...) } -func (v Value) TimeDuration() time.Duration { return gconv.TimeDuration(v.Bytes()) } \ No newline at end of file diff --git a/g/g.go b/g/g.go index c39f16268..8ddabda0a 100644 --- a/g/g.go +++ b/g/g.go @@ -7,6 +7,11 @@ package g +import "gitee.com/johng/gf/g/container/gvar" + +// 框架动态变量,可以用该类型替代interface{}类型 +type Var = gvar.Var + // 常用map数据结构(使用别名) type Map = map[string]interface{} diff --git a/g/g_func.go b/g/g_func.go index 3882bf213..bef7e7fd5 100644 --- a/g/g_func.go +++ b/g/g_func.go @@ -10,6 +10,7 @@ import ( "gitee.com/johng/gf/g/net/ghttp" "gitee.com/johng/gf/g/util/gutil" "gitee.com/johng/gf/g/os/glog" + "gitee.com/johng/gf/g/container/gvar" ) const ( @@ -22,6 +23,11 @@ const ( LOG_LEVEL_CRIT = glog.LEVEL_CRIT ) +// 动态变量 +func NewVar(i interface{}, safe...bool) *Var { + return gvar.New(i, safe...) +} + // 阻塞等待HTTPServer执行完成(同一进程多HTTPServer情况下) func Wait() { ghttp.Wait() diff --git a/g/net/ghttp/ghttp_request.go b/g/net/ghttp/ghttp_request.go index 220fc0e64..23c86f53e 100644 --- a/g/net/ghttp/ghttp_request.go +++ b/g/net/ghttp/ghttp_request.go @@ -15,6 +15,7 @@ import ( "gitee.com/johng/gf/g/os/gtime" "github.com/fatih/structs" "strings" + "gitee.com/johng/gf/g/container/gvar" ) // 请求对象 @@ -79,6 +80,10 @@ func (r *Request) Get(key string, def ... string) string { return r.GetRequestString(key, def...) } +func (r *Request) GetVar(key string, def ... interface{}) *gvar.Var { + return r.GetRequestVar(key, def...) +} + // 获取原始请求输入字符串,注意:只能获取一次,读完就没了 func (r *Request) GetRaw() []byte { result, _ := ioutil.ReadAll(r.Body) diff --git a/g/net/ghttp/ghttp_request_request.go b/g/net/ghttp/ghttp_request_request.go index 35c53d856..a601b9afc 100644 --- a/g/net/ghttp/ghttp_request_request.go +++ b/g/net/ghttp/ghttp_request_request.go @@ -8,6 +8,7 @@ package ghttp import ( "gitee.com/johng/gf/g/util/gconv" + "gitee.com/johng/gf/g/container/gvar" ) // 获得router、post或者get提交的参数,如果有同名参数,那么按照router->get->post优先级进行覆盖 @@ -25,6 +26,17 @@ func (r *Request) GetRequest(key string, def ... []string) []string { return v } +func (r *Request) GetRequestVar(key string, def ... interface{}) *gvar.Var { + value := r.GetRequest(key) + if value != nil { + return gvar.New(value) + } + if len(def) > 0 { + return gvar.New(def[0]) + } + return nil +} + func (r *Request) GetRequestString(key string, def ... string) string { value := r.GetRequest(key) if value != nil && value[0] != "" { diff --git a/g/util/gconv/gconv_struct.go b/g/util/gconv/gconv_struct.go index 245ab9f52..b59177cfd 100644 --- a/g/util/gconv/gconv_struct.go +++ b/g/util/gconv/gconv_struct.go @@ -122,13 +122,15 @@ func getTagMapOfStruct(objPointer interface{}) map[string]string { // 将参数值绑定到对象指定名称的属性上 func bindVarToStruct(elem reflect.Value, name string, value interface{}) error { structFieldValue := elem.FieldByName(name) - // 键名与对象属性匹配检测 + // 键名与对象属性匹配检测,map中如果有struct不存在的属性,那么不做处理,直接return if !structFieldValue.IsValid() { - return errors.New(fmt.Sprintf(`invalid struct attribute of name "%s"`, name)) + //return errors.New(fmt.Sprintf(`invalid struct attribute of name "%s"`, name)) + return nil } // CanSet的属性必须为公开属性(首字母大写) if !structFieldValue.CanSet() { - return errors.New(fmt.Sprintf(`struct attribute of name "%s" cannot be set`, name)) + //return errors.New(fmt.Sprintf(`struct attribute of name "%s" cannot be set`, name)) + return nil } // 必须将value转换为struct属性的数据类型,这里必须用到gconv包 defer func() { @@ -146,11 +148,13 @@ func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) er structFieldValue := elem.FieldByIndex([]int{index}) // 键名与对象属性匹配检测 if !structFieldValue.IsValid() { - return errors.New(fmt.Sprintf("invalid struct attribute at index %d", index)) + //return errors.New(fmt.Sprintf("invalid struct attribute at index %d", index)) + return nil } // CanSet的属性必须为公开属性(首字母大写) if !structFieldValue.CanSet() { - return errors.New(fmt.Sprintf("struct attribute cannot be set at index %d", index)) + //return errors.New(fmt.Sprintf("struct attribute cannot be set at index %d", index)) + return nil } // 必须将value转换为struct属性的数据类型,这里必须用到gconv包 defer func() { diff --git a/geg/database/orm/mysql/gdb_value.go b/geg/database/orm/mysql/gdb_value.go new file mode 100644 index 000000000..d533806ec --- /dev/null +++ b/geg/database/orm/mysql/gdb_value.go @@ -0,0 +1,31 @@ +package main + +import ( + "gitee.com/johng/gf/g/database/gdb" + "fmt" +) + +func main() { + gdb.AddDefaultConfigNode(gdb.ConfigNode { + Host : "127.0.0.1", + Port : "3306", + User : "root", + Pass : "123456", + Name : "test", + Type : "mysql", + Role : "master", + Charset : "utf8", + }) + db, err := gdb.New() + if err != nil { + panic(err) + } + // 开启调试模式,以便于记录所有执行的SQL + db.SetDebug(true) + + r, _ := db.Table("user").Where("uid=?", 1).One() + if r != nil { + fmt.Println(r["uid"].Int()) + fmt.Println(r["name"].String()) + } +} \ No newline at end of file diff --git a/geg/other/test.go b/geg/other/test.go index 62b8975be..7b8d1d9b6 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -1,8 +1,8 @@ package main import ( + "gitee.com/johng/gf/g" "fmt" - "reflect" ) type S struct { @@ -10,12 +10,7 @@ type S struct { } func main() { - s := S{} - fmt.Println(reflect.ValueOf(s).Kind()) - fmt.Println(reflect.ValueOf(&s).Elem().Kind()) - - v := reflect.ValueOf(s).Interface() - fmt.Println(reflect.ValueOf(v).Kind()) - fmt.Println(reflect.ValueOf(&v).Elem().Type().PkgPath()) + v := g.NewVar(nil) + fmt.Println(v.Val()) }