<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在資料傳遞時,需要先編解碼;常用的方式是JSON編解碼(參見《golang之JSON處理》)。但有時卻需要讀取部分欄位後,才能知道具體型別,此時就可藉助mapstructure庫了。
mapstructure可方便地實現map[string]interface{}
與struct
間的轉換;使用前,需要先匯入庫:
go get github.com/mitchellh/mapstructure
預設情況下,mapstructure使用欄位的名稱做匹配對映(即在map中以欄位名為鍵值查詢欄位值);注意匹配時是忽略大小寫的。也可通過標籤來設定欄位對映名稱:
type Person struct { Name string `mapstructure:"userName"` }
go中結構體是可以任意巢狀的;巢狀後即認為擁有對應的欄位。但是,預設情況下mapstructure只處理當前結構定義的欄位,若要自動處理內嵌欄位需要新增標籤squash
:
type Student struct { Person `mapstructure:",squash"` Age int }
若源資料中有未對映的值(即結構體中無對應的欄位),mapstructure預設會忽略它。可以在結構體中定義一個特殊欄位(型別為map[string]interface{}
,且標籤要設定為mapstructure:",remain"
),來存放所有未能對映的欄位中。
type Student struct { Name string Age int Other map[string]interface{} `mapstructure:",remain"` }
mapstructure中可以使用Metadata收集一些解碼時會產生的有用資訊。
// mapstructure.go type Metadata struct { Keys []string // 解碼成功的鍵 Unused []string // 源資料中存在,但目標結構中不存在的鍵 Unset []string // 未設定的(源資料中缺失的)鍵 }
為了獲取這些資訊,需要使用DecodeMetadata來解碼:
var metadata mapstructure.Metadata
err := mapstructure.DecodeMetadata(m, &p, &metadata)
有時候,並不想對結構體欄位型別和map[string]interface{}
的對應鍵值做強型別一致的校驗。這時可以使用WeakDecode/WeakDecodeMetadata方法,它們會嘗試做型別轉換:
除將map轉換為結構體外,mapstructure也可以將結構體反向解碼為map[string]interface{}
。在反向解碼時,我們可以為某些欄位設定mapstructure:“,omitempty”,當這些欄位為預設值時,就不會出現在map中:
p := &Student{ Name: "Mike", Age: 12, } var m map[string]interface{} mapstructure.Decode(p, &m)
mapstructure提供瞭解碼器(Decoder),可靈活方便地控制解碼:
type DecoderConfig struct { // 若設定,則在任何解碼或型別轉換(設定了WeaklyTypedInput)前呼叫;對於設定了squash的內嵌欄位,整體呼叫一次;若返回錯誤,則整個解碼失敗 DecodeHook DecodeHookFunc // 若設定,則源資料中存在未使用欄位時,報錯 ErrorUnused bool // 若設定,則有欄位未設定時,報錯 ErrorUnset bool // 若設定,則在設定欄位前先清空(對於map等型別會先清理掉舊資料) ZeroFields bool // 若設定,支援若型別間的轉換 WeaklyTypedInput bool // Squash will squash embedded structs. Squash bool // Metadata is the struct that will contain extra metadata about // the decoding. If this is nil, then no metadata will be tracked. Metadata *Metadata // Result is a pointer to the struct that will contain the decoded // value. Result interface{} // The tag name that mapstructure reads for field names. This // defaults to "mapstructure" TagName string // IgnoreUntaggedFields ignores all struct fields without explicit // TagName, comparable to `mapstructure:"-"` as default behaviour. IgnoreUntaggedFields bool // MatchName is the function used to match the map key to the struct // field name or tag. Defaults to `strings.EqualFold`. This can be used // to implement case-sensitive tag values, support snake casing, etc. MatchName func(mapKey, fieldName string) bool }
一個支援弱型別轉換的範例:要獲取的結果放到config的result中
Name string Age int } func decoderConfig() { m := map[string]interface{}{ "name": 123, "age": "12", "job": "programmer", } var p Person var metadata mapstructure.Metadata decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ WeaklyTypedInput: true, Result: &p, Metadata: &metadata, }) if err != nil { log.Fatal(err) } err = decoder.Decode(m) if err == nil { log.Printf("Result: %#v", p) log.Printf("keys:%#v, unused:%#vn", metadata.Keys, metadata.Unused) } else { log.Println("decode fail:", err) } }
通過一個messageData結構,action會指示最終的data型別。接收到資料後,先解析出atcion,再根據action轉換為真實的型別。
因time.Time是一個結構體(json序列化時會轉換為時間字串),mapstructure無法正確處理,所以推薦使用時間戳。
為了能正確解析內嵌的DataBasic,需要標記為squash。
import "github.com/mitchellh/mapstructure" type DataBasic struct { DataId string `json:"dataId"` UpdateTime int64 `json:"updateTime"` } type AddedData struct { DataBasic `mapstructure:",squash"` Tag string `json:"tag"` AddParams map[string]any `json:"addParams"` } type messageData struct { Action int `json:"action"` SeqId uint64 `json:"seqId"` Data any `json:"data"` } func decodeData() { add := &AddedData{ DataBasic: DataBasic{ DataId: "a2", UpdateTime: time.Now().UnixMilli(), }, Tag: "tag", AddParams: map[string]any{"dataId": "c2", "otherId": "t2"}, } data := &messageData{ Action: 1, Data: add, } js, err := json.Marshal(data) if err != nil { log.Printf("marshal fail: %v", err) return } got := &messageData{} err = json.Unmarshal(js, got) if err != nil { log.Printf("unmarshal fail: %v", err) return } param := new(AddedData) err = mapstructure.Decode(got.Data, param) if err != nil { log.Printf("unmarshal fail: %v", err) return } log.Printf("param: %+v", param) }
到此這篇關於Golang中結構體對映mapstructure庫深入詳解的文章就介紹到這了,更多相關Go mapstructure內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45