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還有更多詳細的用法,可供參考。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章