项目中我们经常会遇到大量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://godoc.org/github.com/gogf/gf/util/gconv
转换规则
gconv模块的struct转换特性非常强大,支持任意数据类型到struct属性的映射转换。在没有提供自定义mapping转换规则的情况下,默认的转换规则如下:
- struct中需要匹配的属性必须为 公开属性 (首字母大写)。
- 根据params类型的不同,逻辑会有不同:
- params参数类型为map:键名会自动按照 不区分大小写 且 忽略特殊字符 的形式与struct属性进行匹配。
- params参数为其他类型:将会把该变量值与struct的第一个属性进行匹配。
- 此外,如果struct的属性为复杂数据类型如slice,map,strcut那么会进行递归匹配赋值。
- 如果匹配成功,那么将键值赋值给属性,如果无法匹配,那么忽略该键值。
以下是几个map键名与struct属性名称的示例:
map键名 struct属性 是否匹配name Name matchEmail Email matchnickname NickName matchNICKNAME NickName matchNick-Name NickName matchnick_name NickName matchnick name NickName matchNickName Nick_Name matchNick-name Nick_Name matchnick_name Nick_Name matchnick name Nick_Name match
自动创建对象
当给定的pointer参数类型为**struct时,Struct方法内部将会自动创建该struct对象,并修改传递变量指向的指针地址。
package mainimport ("github.com/gogf/gf/frame/g""github.com/gogf/gf/util/gconv")func main() {type User struct {Uid intName string}params := g.Map{"uid": 1,"name": "john",}var user *Userif err := gconv.Struct(params, &user); err != nil {panic(err)}g.Dump(user)}
执行后,输出结果为:
{"Name": "john","Uid": 1}
Struct递归转换
递归转换是指当struct对象包含子对象时,并且子对象是embedded方式定义时,可以将params参数数据(第一个参数)同时递归地映射到其子对象上,常用于带有继承对象的struct上。
package mainimport ("github.com/gogf/gf/frame/g""github.com/gogf/gf/util/gconv")func main() {// g.Server().Run()type Ids struct {Id int `json:"id"`Uid int `json:"uid"`}type Base struct {IdsCreateTime string `json:"create_time"`}type User struct {Bases BasePassport string `json:"passport"`Password string `json:"password"`Nickname string `json:"nickname"`}data := g.Map{"Bases": g.Map{"id": 100, "uid": 1, "create_time" : "2019",},"passport" : "john","password" : "123456","nickname" : "John",}var user *Usergconv.Struct(data, &user)g.Dump(user)}
执行后,终端输出结果为:
{"Base": {"id": 1,"uid": 100,"create_time": "2019"},"nickname": "John","passport": "john","password": "123456"}
示例1,基本使用
package mainimport ("github.com/gogf/gf/frame/g""github.com/gogf/gf/util/gconv")type User struct {Uid intName stringSiteUrl stringNickName stringPass1 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 mainimport ("github.com/gogf/gf/util/gconv""github.com/gogf/gf/frame/g""fmt")func main() {type Score struct {Name stringResult 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}}
