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