Go:mapstructure包的使用

参考:goinggo/mapstructure
参考:package mapstructure

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.com/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.com/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.com/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还有更多详细的用法,可供参考。

发布了117 篇原创文章 · 获赞 15 · 访问量 5602

猜你喜欢

转载自blog.csdn.net/qq_34326321/article/details/105123996