- Struct转换
- 转换规则
- 自动初始化
Struct递归转换- 示例1,基本使用
- 示例2,复杂类型
- 1.
slice类型属性 - 2.
struct属性为struct/*struct - 3.
struct属性为slice,数值为slice - 4.
struct属性为slice,数值为非slice - 5.
struct属性为[]*struct
- 1.
Struct转换
项目中我们经常会遇到大量struct的使用,以及各种数据类型到struct的转换/赋值(特别是json/xml/各种协议编码转换的时候)。为提高编码及项目维护效率,gconv模块为各位开发者带来了极大的福利,为数据解析提供了更高的灵活度。
gconv模块执行struct转换的方法仅有两个,定义如下:
func Struct(params interface{}, pointer interface{}, mapping ...map[string]string) errorfunc StructDeep(params interface{}, pointer interface{}, mapping ...map[string]string) error
其中:
params为需要转换到struct的变量参数,可以为任意数据类型,常见的数据类型为map;pointer为需要执行转的目标struct对象,这个参数必须为该struct的对象指针,转换成功后该对象的属性将会更新;mapping为自定义的map键名到strcut属性之间的映射关系,此时params参数必须为map类型,否则该参数无意义;StructDeep相比较于Struct方法,区别是支持递归转换,即会同时递归转换其属性中的结构体对象,特别用于转换带有继承结构的自定义struct,详见后续示例;
转换规则
gconv模块的struct转换特性非常强大,支持任意数据类型到struct属性的映射转换。在没有提供自定义mapping转换规则的情况下,默认的转换规则如下:
struct中需要匹配的属性必须为公开属性(首字母大写);- 根据
params类型的不同,逻辑会有不同:params参数为map: 键名会自动按照不区分大小写且 忽略-/_/空格符号 的形式与struct属性进行匹配;params参数为其他类型: 将会把该变量值与struct的第一个属性进行匹配;- 此外,如果
struct的属性为复杂数据类型如slice,map,strcut那么会进行递归匹配赋值;
- 如果匹配成功,那么将键值赋值给属性,如果无法匹配,那么忽略该键值;
以下是几个匹配的示例:
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方法内部将会自动进行初始化创建对象,并修改传递变量指向的指针地址。
package mainimport ("github.com/gogf/gf/g""github.com/gogf/gf/g/util/gconv")func main() {type User struct {Uid intName string}user := (*User)(nil)params := g.Map{"uid": 1,"name": "john",}err := gconv.Struct(params, &user)if err != nil {panic(err)}g.Dump(user)}
执行后,输出结果为:
{"Name": "john","Uid": 1}
Struct递归转换
递归转换是指当struct对象包含子对象时,可以将params数据同时递归地映射到其子对象上,常用于带有继承对象的struct上。
可以使用StructDeep方法实现递归转换。
package mainimport ("github.com/gogf/gf/g""github.com/gogf/gf/g/util/gconv")func main() {type Ids struct {Id int `json:"id"`Uid int `json:"uid"`}type Base struct {IdsCreateTime string `json:"create_time"`}type User struct {BasePassport 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.StructDeep(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/g"
"github.com/gogf/gf/g/util/gconv"
)
type User struct {
Uid int
Name string
Site_Url string
NickName string
Pass1 string `gconv:"password1"`
Pass2 string `gconv:"password2"`
}
func main() {
user := (*User)(nil)
// 使用默认映射规则绑定属性值到对象
user = new(User)
params1 := g.Map{
"uid" : 1,
"Name" : "john",
"siteurl" : "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",
"Site_Url": "https://goframe.org",
"NickName": "johng",
"Pass1": "123",
"Pass2": "456"
}
{
"Uid": 2,
"Name": "smith",
"Site_Url": "https://goframe.org",
"NickName": "johng",
"Pass1": "111",
"Pass2": "222"
}
示例2,复杂类型
1. slice类型属性
package main
import (
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/g"
"fmt"
)
// 演示slice类型属性的赋值
func main() {
type User struct {
Scores []int
}
user := new(User)
scores := []interface{}{99, 100, 60, 140}
// 通过map映射转换
if err := gconv.Struct(g.Map{"Scores" : scores}, user); err != nil {
fmt.Println(err)
} else {
g.Dump(user)
}
// 通过变量映射转换,直接slice赋值
if err := gconv.Struct(scores, user); err != nil {
fmt.Println(err)
} else {
g.Dump(user)
}
}
执行后,输出结果为:
{
"Scores": [
99,
100,
60,
140
]
}
{
"Scores": [
99,
100,
60,
140
]
}
2. struct属性为struct/*struct
属性支持struct对象或者struct对象指针(目标为指针时,转换时会自动初始化)转换。
package main
import (
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/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 := map[string]interface{}{
"Scores" : map[string]interface{}{
"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
}
}
3. struct属性为slice,数值为slice
package main
import (
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/g"
"fmt"
)
func main() {
type Score struct {
Name string
Result int
}
type User struct {
Scores []Score
}
user := new(User)
scores := map[string]interface{}{
"Scores" : []interface{}{
map[string]interface{}{
"Name" : "john",
"Result" : 100,
},
map[string]interface{}{
"Name" : "smith",
"Result" : 60,
},
},
}
// 嵌套struct转换,属性为slice类型,数值为slice map类型
if err := gconv.Struct(scores, user); err != nil {
fmt.Println(err)
} else {
g.Dump(user)
}
}
执行后,输出结果为:
{
"Scores": [
{
"Name": "john",
"Result": 100
},
{
"Name": "smith",
"Result": 60
}
]
}
4. struct属性为slice,数值为非slice
package main
import (
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/g"
"fmt"
)
func main() {
type Score struct {
Name string
Result int
}
type User struct {
Scores []Score
}
user := new(User)
scores := map[string]interface{}{
"Scores" : map[string]interface{}{
"Name" : "john",
"Result" : 100,
},
}
// 嵌套struct转换,属性为slice类型,数值为map类型
if err := gconv.Struct(scores, user); err != nil {
fmt.Println(err)
} else {
g.Dump(user)
}
}
执行后,输出结果为:
{
"Scores": [
{
"Name": "john",
"Result": 100
}
]
}
5. struct属性为[]*struct
package main
import (
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/g"
"fmt"
)
func main() {
type Score struct {
Name string
Result int
}
type User struct {
Scores []*Score
}
user := new(User)
scores := map[string]interface{}{
"Scores" : []interface{}{
map[string]interface{}{
"Name" : "john",
"Result" : 100,
},
map[string]interface{}{
"Name" : "smith",
"Result" : 60,
},
},
}
// 嵌套struct转换,属性为slice类型,数值为slice map类型
if err := gconv.Struct(scores, user); err != nil {
fmt.Println(err)
} else {
g.Dump(user)
}
}
执行后,输出结果为:
{
"Scores": [
{
"Name": "john",
"Result": 100
},
{
"Name": "smith",
"Result": 60
}
]
}
