新聞中心
當然,想必您已經(jīng)猜到了,在對一些復(fù)雜類型(如?struct?)的轉(zhuǎn)換時,?gconv?模塊內(nèi)部其實使用了反射的特性來實現(xiàn)的。這雖然為開發(fā)者提供了極大的便捷,但是這確實是以性能損耗為代價的。其實在對于?struct?轉(zhuǎn)換時,如果開發(fā)者已經(jīng)明確轉(zhuǎn)換規(guī)則,并且對于其中的性能損耗比較在意,那么可以對特定的?struct?實現(xiàn)?UnmarshalValue?接口來實現(xiàn)自定義轉(zhuǎn)換。當使用?gconv?模塊對該?struct?進行轉(zhuǎn)換時,無論該?struct?是直接作為轉(zhuǎn)換對象或者作為轉(zhuǎn)換對象的屬性,?gconv?都將會自動識別其實現(xiàn)的?UnmarshalValue?接口并直接調(diào)用該接口實現(xiàn)類型轉(zhuǎn)換,而不會使用反射特性來實現(xiàn)轉(zhuǎn)換。

公司主營業(yè)務(wù):成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)公司是一支青春激揚、勤奮敬業(yè)、活力青春激揚、勤奮敬業(yè)、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴謹、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)公司推出鶴城免費做網(wǎng)站回饋大家。
標準庫的常用反序列化接口,如?UnmarshalText(text []byte) error?其實也是支持的喲,使用方式同?UnmarshalValue?,只是參數(shù)不同。
接口定義
// apiUnmarshalValue is the interface for custom defined types customizing value assignment.
// Note that only pointer can implement interface apiUnmarshalValue.
type apiUnmarshalValue interface {
UnmarshalValue(interface{}) error
}
可以看到,自定義的類型可以通過定義?UnmarshalValue?方法來實現(xiàn)自定義的類型轉(zhuǎn)換。這里的輸入?yún)?shù)為?interface{}?類型,開發(fā)者可以在實際使用場景中通過 類型斷言 或者其他方式進行類型轉(zhuǎn)換。
需要特別注意,由于?UnmarshalValue?類型轉(zhuǎn)換會修改當前對象的屬性值,因此需要保證該接口實現(xiàn)的接受者(?Receiver?)是指針類型。
正確的接口實現(xiàn)定義示例(使用指針接受):
func (c *Receiver) UnmarshalValue(interface{}) error
錯誤的接口實現(xiàn)定義示例(使用了值傳遞):
func (c Receiver) UnmarshalValue(interface{}) error
使用示例
1、自定義數(shù)據(jù)表查詢結(jié)果struct轉(zhuǎn)換
數(shù)據(jù)表結(jié)構(gòu):
CREATE TABLE `user` (
id bigint unsigned NOT NULL AUTO_INCREMENT,
passport varchar(45),
password char(32) NOT NULL,
nickname varchar(45) NOT NULL,
create_time timestamp NOT NULL,
PRIMARY KEY (id)
) ;
示例代碼:
package main
import (
"fmt"
"github.com/GOgf/gf/v2/container/garray"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"reflect"
)
type User struct {
Id int
Passport string
Password string
Nickname string
CreateTime *gtime.Time
}
// 實現(xiàn)UnmarshalValue接口,用于自定義結(jié)構(gòu)體轉(zhuǎn)換
func (user *User) UnmarshalValue(value interface{}) error {
if record, ok := value.(gdb.Record); ok {
*user = User{
Id: record["id"].Int(),
Passport: record["passport"].String(),
Password: "",
Nickname: record["nickname"].String(),
CreateTime: record["create_time"].GTime(),
}
return nil
}
return gerror.Newf(`unsupported value type for UnmarshalValue: %v`, reflect.TypeOf(value))
}
func main() {
var (
err error
users []*User
)
array := garray.New(true)
for i := 1; i <= 10; i++ {
array.Append(g.Map{
"id": i,
"passport": fmt.Sprintf(`user_%d`, i),
"password": fmt.Sprintf(`pass_%d`, i),
"nickname": fmt.Sprintf(`name_%d`, i),
"create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(),
})
}
// 寫入數(shù)據(jù)
_, err = g.Model("user").Data(array).Insert()
if err != nil {
panic(err)
}
// 查詢數(shù)據(jù)
err = g.Model("user").Order("id asc").Scan(&users)
if err != nil {
panic(err)
}
g.Dump(users)
}
執(zhí)行后,終端輸出:
[
{
"Id": 1,
"Passport": "user_1",
"Password": "",
"Nickname": "name_1",
"CreateTime": "2018-10-24 10:00:00"
},
{
"Id": 2,
"Passport": "user_2",
"Password": "",
"Nickname": "name_2",
"CreateTime": "2018-10-24 10:00:00"
},
{
"Id": 3,
"Passport": "user_3",
"Password": "",
"Nickname": "name_3",
"CreateTime": "2018-10-24 10:00:00"
},
{
"Id": 4,
"Passport": "user_4",
"Password": "",
"Nickname": "name_4",
"CreateTime": "2018-10-24 10:00:00"
},
{
"Id": 5,
"Passport": "user_5",
"Password": "",
"Nickname": "name_5",
"CreateTime": "2018-10-24 10:00:00"
},
{
"Id": 6,
"Passport": "user_6",
"Password": "",
"Nickname": "name_6",
"CreateTime": "2018-10-24 10:00:00"
},
{
"Id": 7,
"Passport": "user_7",
"Password": "",
"Nickname": "name_7",
"CreateTime": "2018-10-24 10:00:00"
},
{
"Id": 8,
"Passport": "user_8",
"Password": "",
"Nickname": "name_8",
"CreateTime": "2018-10-24 10:00:00"
},
{
"Id": 9,
"Passport": "user_9",
"Password": "",
"Nickname": "name_9",
"CreateTime": "2018-10-24 10:00:00"
},
{
"Id": 10,
"Passport": "user_10",
"Password": "",
"Nickname": "name_10",
"CreateTime": "2018-10-24 10:00:00"
}
]
可以看到自定義的?UnmarshalValue?類型轉(zhuǎn)換方法中沒有使用到反射特性,因此轉(zhuǎn)換的性能會得到極大的提升。小伙伴們可以嘗試著增加寫入的數(shù)據(jù)量(例如?100W?),同時對比一下去掉?UnmarshalValue?后的類型轉(zhuǎn)換所開銷的時間。
2、自定義二進制TCP數(shù)據(jù)解包
一個?TCP?通信的數(shù)據(jù)包解包示例。
package main
import (
"errors"
"fmt"
"github.com/gogf/gf/v2/crypto/gcrc32"
"github.com/gogf/gf/v2/encoding/gbinary"
"github.com/gogf/gf/v2/util/gconv"
)
type Pkg struct {
Length uint16 // Total length.
Crc32 uint32 // CRC32.
Data []byte
}
// NewPkg creates and returns a package with given data.
func NewPkg(data []byte) *Pkg {
return &Pkg{
Length: uint16(len(data) + 6),
Crc32: gcrc32.Encrypt(data),
Data: data,
}
}
// Marshal encodes the protocol struct to bytes.
func (p *Pkg) Marshal() []byte {
b := make([]byte, 6+len(p.Data))
copy(b, gbinary.EncodeUint16(p.Length))
copy(b[2:], gbinary.EncodeUint32(p.Crc32))
copy(b[6:], p.Data)
return b
}
// UnmarshalValue decodes bytes to protocol struct.
func (p *Pkg) UnmarshalValue(v interface{}) error {
b := gconv.Bytes(v)
if len(b) < 6 {
return errors.New("invalid package length")
}
p.Length = gbinary.DecodeToUint16(b[:2])
if len(b) < int(p.Length) {
return errors.New("invalid data length")
}
p.Crc32 = gbinary.DecodeToUint32(b[2:6])
p.Data = b[6:]
if gcrc32.Encrypt(p.Data) != p.Crc32 {
return errors.New("crc32 validation failed")
}
return nil
}
func main() {
var p1, p2 *Pkg
// Create a demo pkg as p1.
p1 = NewPkg([]byte("123"))
fmt.Println(p1)
// Convert bytes from p1 to p2 using gconv.Struct.
err := gconv.Struct(p1.Marshal(), &p2)
if err != nil {
panic(err)
}
fmt.Println(p2)
}
執(zhí)行后,終端輸出:
&{9 2286445522 [49 50 51]}
&{9 2286445522 [49 50 51]}
本文名稱:創(chuàng)新互聯(lián)GoFrame教程:GoFrame類型轉(zhuǎn)換-UnmarshalValue
網(wǎng)站鏈接:http://www.fisionsoft.com.cn/article/cdgeioe.html


咨詢
建站咨詢
