参考:goinggo/mapstructure
参考:package mapstructure
文章目录
- 1、导包
- 2、使用目的
- 3、Decode:map转换成结构体
- 1、不支持内部结构体转换
- 2、常规转换
- 3、结论
- 4、DecodePath:复制内部某个结构体
- 1、代码
- 2、注意点
- 3、time.Time的转换
- 4、使用Decode方法替代
- 5、DecodeSlicePath:结构化切片
- 1、切片处理
- 2、结构体中包含切片的处理
1、导包
如果是Idea的话,在我们的Terminal上面输入命令,进行包的获取:
go get github.com/goinggo/mapstructure
正常是不会有问题,如果下载不下来报permission denie可以看一下我的这个文章:Git下载报错: Permission denied (publickey).问题解决
2、使用目的
官网的描述是这样的:
我的理解是说像map之类的结构,虽然用起来很方便,但是他麻烦的地方在于对于相应的结构信息不清晰,也就是说当你纯看代码的时候可能不知道具体里面有什么东西,而结构体就比较明确,他有多少属性, 什么类型等等,所以这里使用这个工具把map、json之类的进行转换其实也是为了能够得到结构体对象,数据结构更加清晰。
3、Decode:map转换成结构体
1、不支持内部结构体转换
看一下这一段代码,我这边添加了一个time的属性,本质上time是结构体,所以正常来说是不支持转换的。
Entity对象:
package entity
import "time"
type Entity struct {
Num int
S string
T time.Time
}
调用方法:
package main
import (
"fmt"
"github/goinggo/mapstructure"
"testProject/entity"
"time"
)
func MapStructureTestFunc() {
var te entity.Entity
m := make(map[string]interface{})
m["Num"] = 1
m["S"] = "test"
m["T"] = time.Now()
err := mapstructure.Decode(m, &te)
if err != nil {
panic(err.Error())
}
fmt.Print(te.Num, " ", te.S, " ", te.T)
}
直接运行我们这段代码看一下,断点在err处:
发现这边报了个错,不支持struct结构体的类型。但是可以支持map。
2、常规转换
所以我们把这边的T
换成了map类型:
Entity对象:
package entity
type Entity struct {
Num int
S string
T map[string]string
}
运行方法:
package main
import (
"fmt"
"github/goinggo/mapstructure"
"testProject/entity"
)
func MapStructureTestFunc() {
var te entity.Entity
m := make(map[string]interface{})
m["Num"] = 1
m["S"] = "test"
m["T"] = map[string]string{"1": "1", "2": "2"}
err := mapstructure.Decode(m, &te)
if err != nil {
panic(err.Error())
}
fmt.Print(te.Num, " ", te.S, " ", te.T)
}
这一次没有报错了,查看一下我们的输出:
3、结论
1、该方法支持基本类型,不支持结构体 struct
2、该方法支持map结构中的值是map的嵌套结构
其实想来在java当中的BeanUtils的复制功能可能更强大一点,通过内省的方式实现同名类型的赋值。这里应该是没有考虑泛型的处理,之前看了源码太久忘了,java的对象操作,泛型相关的确实非常烦人。
4、DecodePath:复制内部某个结构体
1、代码
其实这个方法也是把整个的报文结构体复制下来,然后取其中的一些部分,怎么说呢,就是说他支持结构体中嵌套结构体的转换,而其实你取的只是其中一部分而已。我们看一下代码:
User实体
package entity
import "time"
type UserType struct {
UserTypeId int
UserTypeName string
}
type User struct {
UserType UserType `jpath:"userType"`
LoginName string `jpath:"loginName"`
T time.Time `jpath:"t"`
}
主方法:
package main
import (
"encoding/json"
"fmt"
"github/goinggo/mapstructure"
"testProject/entity"
)
var document = `{"loginName":"sptest1","userType":{"userTypeId":1,"userTypeName":"normal_user","t":"2026-01-02 15:04:05"}}`
func MapStructureTestFunc() {
var te entity.Entity
m := make(map[string]interface{})
m["Num"] = 1
m["S"] = "test"
m["T"] = map[string]string{"1": "1", "2": "2"}
err := mapstructure.Decode(m, &te)
if err != nil {
panic(err.Error())
}
fmt.Print(te.Num, " ", te.S, " ", te.T)
}
func MapStructureTestFunc1() {
var docMap map[string]interface{}
_ = json.Unmarshal([]byte(document), &docMap)
var user entity.User
err := mapstructure.DecodePath(docMap, &user)
if err != nil {
panic(err.Error())
}
fmt.Println(user.T.Format("2006-01-02 15:04:05"))
fmt.Println(user, " ", user.UserType.UserTypeId, " ", user.UserType.UserTypeName)
}
2、注意点
注意: 实体中的jpath
的意思是结构体在数据中的别名,结构体字段必须是大写(非私有)才可见。
注意: 之前看网上有文章说字段和值得书写风格不一样转换不出来,我感觉这个很傻逼,如果真这么做的话那这个写api的人得花多少功夫去比较。
3、time.Time的转换
最后我尝试了一下这边的时间字段,无论是什么时间,好像都只会被转换成统一的数值,表示有点奇怪,这个还是没弄明白为啥
4、使用Decode方法替代
这边尝试了一下使用Decode方法也可以达到相应的目的,那这两个方法究竟有什么区别
5、DecodeSlicePath:结构化切片
1、切片处理
如果是对切片的结构进行处理的话,直接使用DecodeSlicePath方法,我们来看下面的代码:
NameDoc实体
type NameDoc struct {
Name string `jpath:"name"`
}
主方法:
var document2 = `[{"name":"bill"},{"name":"lisa"}]`
func MapStructureTestFunc2() {
sliceScript := []byte(document2)
var sliceMap []map[string]interface{}
_ = json.Unmarshal(sliceScript, &sliceMap)
var myslice []NameDoc
err := mapstructure.DecodeSlicePath(sliceMap, &myslice)
if err != nil {
panic(err.Error())
}
fmt.Println(myslice[0], " ", myslice[1])
}
直接输出是正常的。其实还是不要忘了jpath
这个东西.
2、结构体中包含切片的处理
如果说是一个结构体里面包含了切片的结构,比如说下面这个json串,使用DecodePath
方法,按道理来说Decode
方法应该也可以
Json串
{
"cobrandId": 10010352,
"channelId": -1,
"locale": "en_US",
"tncVersion": 2,
"people": [
{
"name": "jack",
"age": {
"birth":10,
"year":2000,
"animals": [
{
"barks":"yes",
"tail":"yes"
},
{
"barks":"no",
"tail":"yes"
}
]
}
},
{
"name": "jill",
"age": {
"birth":11,
"year":2001
}
}
]
}
看一下代码:
实体:
type Animal struct {
Barks string `jpath:"barks"`
}
type People struct {
Age int `jpath:"age.birth"` // jpath is relative to the array
Animals []Animal `jpath:"age.animals"`
}
type Items struct {
Categories []string `jpath:"categories"`
Peoples []People `jpath:"people"` // Specify the location of the array
}
主函数
var document1 = `{"cobrandId":10010352,"channelId":-1,"locale":"en_US","tncVersion":2,"people":[{"name":"jack","age":{"birth":10,"year":2000,"animals":[{"barks":"yes","tail":"yes"},{"barks":"no","tail":"yes"}]}},{"name":"jill","age":{"birth":11,"year":2001}}]}`
func MapStructureTestFunc3() {
docScript := []byte(document1)
var docMap map[string]interface{}
_ = json.Unmarshal(docScript, &docMap)
var items Items
err := mapstructure.DecodePath(docMap, &items)
if err != nil {
panic(err.Error())
}
fmt.Println(items.Peoples[0], items.Peoples[1])
}
官方doc还有更多详细的用法,可供参考。
更多推荐
Go:mapstructure包的使用
发布评论