- Created by 郭强, last modified by 张金富 on May 19, 2023
You are viewing an old version of this page. View the current version.
Compare with Current View Page History
Version 10 Next »
项目中我们经常会遇到大量struct
的使用,以及各种数据类型到struct
的转换/赋值(特别是json
/xml
/各种协议编码转换)。为提高编码及项目维护效率,gconv
模块为各位开发者带来了极大的福利,为数据解析提供了更高的灵活度。
gconv
模块通过Struct
转换方法执行struct
类型转换,其定义如下:
// Struct maps the params key-value pairs to the corresponding struct object's attributes. // The third parameter `mapping` is unnecessary, indicating the mapping rules between the // custom key name and the attribute name(case sensitive). // // Note: // 1. The `params` can be any type of map/struct, usually a map. // 2. The `pointer` should be type of *struct/**struct, which is a pointer to struct object // or struct pointer. // 3. Only the public attributes of struct object can be mapped. // 4. If `params` is a map, the key of the map `params` can be lowercase. // It will automatically convert the first letter of the key to uppercase // in mapping procedure to do the matching. // It ignores the map key, if it does not match. func Struct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error)
其中:
params
为需要转换到struct
的变量参数,可以为任意数据类型,常见的数据类型为map
。pointer
为需要执行转的目标struct
对象,这个参数必须为该struct
的对象指针,转换成功后该对象的属性将会更新。mapping
为自定义的map键名
到strcut属性
之间的映射关系,此时params
参数必须为map
类型,否则该参数无意义。大部分场景下使用可以不用提供该参数,直接使用默认的转换规则即可。
更多的struct
相关转换方法请参考接口文档:https://pkg.go.dev/github.com/gogf/gf/v2/util/gconv
转换规则
gconv
模块的struct
转换特性非常强大,支持任意数据类型到struct
属性的映射转换。在没有提供自定义mapping
转换规则的情况下,默认的转换规则如下:
struct
中需要匹配的属性必须为 公开属性 (首字母大写)。- 根据
params
类型的不同,逻辑会有不同:params
参数类型为map
:键名会自动按照 不区分大小写 且 忽略特殊字符 的形式与struct属性进行匹配。params
参数为其他类型:将会把该变量值与struct
的第一个属性进行匹配。- 此外,如果
struct
的属性为复杂数据类型如slice
,map
,strcut
那么会进行递归匹配赋值。
- 如果匹配成功,那么将键值赋值给属性,如果无法匹配,那么忽略该键值。
以下是几个map
键名与struct
属性名称的示例:
map键名 struct属性 是否匹配 name Name match Email Email match nickname NickName match NICKNAME NickName match Nick-Name NickName match nick_name NickName match nick name NickName match NickName Nick_Name match Nick-name Nick_Name match nick_name Nick_Name match nick name Nick_Name match
自动创建对象
当给定的pointer
参数类型为**struct
时,Struct
方法内部将会自动创建该struct
对象,并修改传递变量指向的指针地址。
package main import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" ) func main() { type User struct { Uid int Name string } params := g.Map{ "uid": 1, "name": "john", } var user *User if err := gconv.Struct(params, &user); err != nil { panic(err) } g.Dump(user) }
执行后,输出结果为:
{ Uid: 1, Name: "john", }
Struct
递归转换
递归转换是指当struct
对象包含子对象时,并且子对象是embedded
方式定义时,可以将params
参数数据(第一个参数)同时递归地映射到其子对象上,常用于带有继承对象的struct
上。
package main import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" ) func main() { type Ids struct { Id int `json:"id"` Uid int `json:"uid"` } type Base struct { Ids CreateTime string `json:"create_time"` } type User struct { Base Passport string `json:"passport"` Password string `json:"password"` Nickname string `json:"nickname"` } data := g.Map{ "id" : 1, "uid" : 100, "passport" : "john", "password" : "123456", "nickname" : "John", "create_time" : "2019", } user := new(User) gconv.Struct(data, user) g.Dump(user) }
执行后,终端输出结果为:
{ "Base": { "id": 1, "uid": 100, "create_time": "2019" }, "nickname": "John", "passport": "john", "password": "123456" }
示例1,基本使用
package main import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" ) type User struct { Uid int Name string SiteUrl string NickName string Pass1 string `c:"password1"` Pass2 string `c:"password2"` } func main() { var user *User // 使用默认映射规则绑定属性值到对象 user = new(User) params1 := g.Map{ "uid": 1, "Name": "john", "site_url": "https://goframe.org", "nick_name": "johng", "PASS1": "123", "PASS2": "456", } if err := gconv.Struct(params1, user); err == nil { g.Dump(user) } // 使用struct tag映射绑定属性值到对象 user = new(User) params2 := g.Map{ "uid": 2, "name": "smith", "site-url": "https://goframe.org", "nick name": "johng", "password1": "111", "password2": "222", } if err := gconv.Struct(params2, user); err == nil { g.Dump(user) } }
可以看到,我们可以直接通过Struct
方法将map
按照默认规则绑定到struct
上,也可以使用struct tag
的方式进行灵活的设置。此外,Struct
方法有第三个map
参数,用于指定自定义的参数名称到属性名称的映射关系。
执行后,输出结果为:
{ "Uid": 1, "Name": "john", "SiteUrl": "https://goframe.org", "NickName": "johng", "Pass1": "123", "Pass2": "456" } { "Uid": 2, "Name": "smith", "SiteUrl": "https://goframe.org", "NickName": "johng", "Pass1": "111", "Pass2": "222" }
示例2,复杂属性类型
属性支持struct
对象或者struct
对象指针(目标为指针且未nil
时,转换时会自动初始化)转换。
package main import ( "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/frame/g" "fmt" ) func main() { type Score struct { Name string Result int } type User1 struct { Scores Score } type User2 struct { Scores *Score } user1 := new(User1) user2 := new(User2) scores := g.Map{ "Scores": g.Map{ "Name": "john", "Result": 100, }, } if err := gconv.Struct(scores, user1); err != nil { fmt.Println(err) } else { g.Dump(user1) } if err := gconv.Struct(scores, user2); err != nil { fmt.Println(err) } else { g.Dump(user2) } }
执行后,输出结果为:
{ "Scores": { "Name": "john", "Result": 100 } } { "Scores": { "Name": "john", "Result": 100 } }
- No labels