日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

技巧:Go 结构体如何转换成 map[string]interface{}

發布時間:2024/4/11 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 技巧:Go 结构体如何转换成 map[string]interface{} 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文介紹了Go語言中將結構體轉成map[string]interface{}時你需要了解的“坑”,也有你需要知道的若干方法。

我們在Go語言中通常使用結構體來保存我們的數據,例如要存儲用戶信息,我們可能會定義如下結構體:

// UserInfo 用戶信息 type UserInfo struct {Name string `json:"name"`Age int `json:"age"` }u1 := UserInfo{Name: "q1mi", Age: 18}

假設現在要將上面的u1轉換成map[string]interface{},該如何操作呢?

結構體轉map[string]interface{}

JSON序列化方式

這不是很簡單嗎?我用json序列化一下u1,再反序列化成map不就可以了么。說干就干,代碼如下:

func main() {u1 := UserInfo{Name: "q1mi", Age: 18}b, _ := json.Marshal(&u1)var m map[string]interface{}_ = json.Unmarshal(b, &m)for k, v := range m{fmt.Printf("key:%v value:%v\n", k, v)} }

輸出:

key:name value:q1mi key:age value:18

看起來沒什么問題,但其實這里是有一個“坑”的。那就是Go語言中的json包在序列化空接口存放的數字類型(整型、浮點型等)都會序列化成float64類型。

也就是上面例子中m["age"]現在底層是一個float64了,不是個int了。我們來驗證下:

func main() {u1 := UserInfo{Name: "q1mi", Age: 18}b, _ := json.Marshal(&u1)var m map[string]interface{}_ = json.Unmarshal(b, &m)for k, v := range m{fmt.Printf("key:%v value:%v value type:%T\n", k, v, v)} }

輸出:

key:name value:q1mi value type:string key:age value:18 value type:float64

很顯然,出現了一個意料之外的行為,我們得想辦法規避掉。

反射

沒辦法就需要自己動手去實現了。這里使用反射遍歷結構體字段的方式生成map, 具體代碼如下:

// ToMap 結構體轉為Map[string]interface{} func ToMap(in interface{}, tagName string) (map[string]interface{}, error){out := make(map[string]interface{})v := reflect.ValueOf(in)if v.Kind() == reflect.Ptr {v = v.Elem()}if v.Kind() != reflect.Struct { // 非結構體返回錯誤提示return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v)}t := v.Type()// 遍歷結構體字段// 指定tagName值為map中key;字段值為map中valuefor i := 0; i < v.NumField(); i++ {fi := t.Field(i)if tagValue := fi.Tag.Get(tagName); tagValue != "" {out[tagValue] = v.Field(i).Interface()}}return out, nil }

驗證一下:

m2, _ := ToMap(&u1, "json") for k, v := range m2{fmt.Printf("key:%v value:%v value type:%T\n", k, v, v) }

輸出:

key:name value:q1mi value type:string key:age value:18 value type:int

這一次map["age"]的類型就對了的。

第三方庫structs

除了自己使用反射實現,Github上也有現成的輪子,例如第三方庫:https://github.com/fatih/structs。

這個包使用的自定義結構體tag是structs:

// UserInfo 用戶信息 type UserInfo struct {Name string `json:"name" structs:"name"`Age int `json:"age" structs:"age"` }

用法很簡單:

m3 := structs.Map(&u1) for k, v := range m3 {fmt.Printf("key:%v value:%v value type:%T\n", k, v, v) }

structs這個包也有很多其他的使用示例,大家可以去查看文檔。但是需要注意的是目前這個庫已經被作者設置為只讀了。

嵌套結構體轉map[string]interface{}

structs本身是支持嵌套結構體轉map[string]interface{}的,遇到結構體嵌套它會轉換為map[string]interface{}嵌套map[string]interface{}的模式。

我們定義一組嵌套的結構體如下:

// UserInfo 用戶信息 type UserInfo struct {Name string `json:"name" structs:"name"`Age int `json:"age" structs:"age"`Profile `json:"profile" structs:"profile"` }// Profile 配置信息 type Profile struct {Hobby string `json:"hobby" structs:"hobby"` }

聲明結構體變量u1:

u1 := UserInfo{Name: "q1mi", Age: 18, Profile: Profile{"雙色球"}}

第三方庫structs

轉換嵌套結構體的代碼和上面其實是一樣的:

m3 := structs.Map(&u1) for k, v := range m3 {fmt.Printf("key:%v value:%v value type:%T\n", k, v, v) }

輸出結果:

key:name value:q1mi value type:string key:age value:18 value type:int key:profile value:map[hobby:雙色球] value type:map[string]interface {}

從結果來看最后嵌套字段profile是map[string]interface {},屬于map嵌套map。

使用反射轉成單層map

如果我們想把嵌套的結構體轉換成一個單層map該怎么做呢?

我們只需要把上面反射的代碼稍微修改一下就可以了,修改后的代碼如下:

// ToMap2 將結構體轉為單層map func ToMap2(in interface{}, tag string) (map[string]interface{}, error) {// 當前函數只接收struct類型v := reflect.ValueOf(in)if v.Kind() == reflect.Ptr { // 結構體指針v = v.Elem()}if v.Kind() != reflect.Struct {return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v)}out := make(map[string]interface{}, 8)queue := make([]interface{}, 0, 2)queue = append(queue, in)for len(queue) > 0 {v := reflect.ValueOf(queue[0])if v.Kind() == reflect.Ptr { // 結構體指針v = v.Elem()}queue = queue[1:]t := v.Type()for i := 0; i < v.NumField(); i++ {vi := v.Field(i)if vi.Kind() == reflect.Ptr { // 內嵌指針vi = vi.Elem()if vi.Kind() == reflect.Struct { // 結構體queue = append(queue, vi.Interface())} else {ti := t.Field(i)if tagValue := ti.Tag.Get(tag); tagValue != "" {// 存入mapout[tagValue] = vi.Interface()}}break}if vi.Kind() == reflect.Struct { // 內嵌結構體queue = append(queue, vi.Interface())break}// 一般字段ti := t.Field(i)if tagValue := ti.Tag.Get(tag); tagValue != "" {// 存入mapout[tagValue] = vi.Interface()}}}return out, nil }

測試一下:

m4, _ := ToMap2(&u1, "json") for k, v := range m4 {fmt.Printf("key:%v value:%v value type:%T\n", k, v, v) }

輸出:

key:name value:q1mi value type:string key:age value:18 value type:int key:hobby value:雙色球 value type:string

這下我們就把嵌套的結構體轉為單層的map了,但是要注意這種場景下結構體和嵌套結構體的字段就需要避免重復。

總結

以上是生活随笔為你收集整理的技巧:Go 结构体如何转换成 map[string]interface{}的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产精品视频免费网站 | www国产精品内射熟女 | 亚洲一区欧洲二区 | 毛片高清 | 全部免费毛片在线播放高潮 | 日日噜噜噜夜夜爽爽狠狠视频97 | 精品国产成人亚洲午夜福利 | 大伊人网 | 亚洲人交配视频 | 国产午夜免费福利 | 黄色aaaaa | 亚洲精品www. | 曰本黄色片 | 国产99久久久国产精品成人免费 | 天天操天天摸天天干 | 欧美成年人视频在线观看 | 好吊妞视频一区二区三区 | www黄色片 | 欧美狠狠 | 亚洲gay视频 | 青青久久av北条麻妃黑人 | 国产馆在线观看 | 少妇又白又嫩又色又粗 | 差差差30分钟 | 国产女主播在线观看 | 日韩bbw | 操操操免费视频 | 日韩av无码一区二区三区不卡 | 免费毛片一级 | 三叶草欧洲码在线 | 国产精品美女久久久久 | 免费人成视频在线播放 | 免费的理伦片在线播放 | 久久久久香蕉视频 | 免费一级片网址 | 免费国产区 | 中文字幕av一区二区三区谷原希美 | 亚洲av永久中文无码精品综合 | 2019中文字幕在线 | 国产高清一 | 日本在线一区二区三区 | 亚洲成年人专区 | 久久久久亚洲av成人毛片韩 | 日本乱子伦 | 国产ts系列 | 午夜av中文字幕 | 999福利视频| 亚洲a中文字幕 | 91网站在线看 | 午夜99 | 国产人妻一区二区三区四区五区六 | 人妻偷人精品一区二区三区 | 久久精品99国产国产精 | 日韩精品电影一区二区三区 | 手机在线永久免费观看av片 | 亚洲一区二区黄色 | 尤物视频在线看 | 女人的黄色片 | 亚洲熟女乱色综合亚洲小说 | 亚洲第一看片 | 青青草香蕉 | 国产在线观看免费播放 | 色01看片网 | 乱码一区二区三区 | 人妖一级片 | 欧美第二页 | 亚洲精品久久久蜜桃网尤妮丝 | 国产日韩专区 | sm在线观看| www.国产欧美 | 天堂网91| 久草综合网 | 国产精品麻豆一区 | 国产亲伦免费视频播放 | 极品销魂美女一区二区 | 中国亚洲女人69内射少妇 | 青青草视频免费看 | 精品少妇人妻av免费久久久 | 国产激情av在线 | 天天在线免费视频 | 大奶在线播放 | 99福利视频| 国产喷水福利在线视频 | 欧美高清hd18日本 | 日本欧美国产在线 | 亚洲AV无码精品一区二区三区 | 久操国产 | 黄色av网站免费在线观看 | 手机免费av | 国产熟妇与子伦hd | 久久久久久久久久久综合 | 台湾佬美性中文 | 超碰免费在线 | av日韩一区二区三区 | 啪啪影音 | 91久久精品一区二区三区 | 成人永久视频 | aa毛片视频 | 日韩图片区 |