日韩性视频-久久久蜜桃-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{}的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 精品国产av 无码一区二区三区 | 亚洲无套 | 青青久操 | 第一福利丝瓜av导航 | 亚洲Av无码成人精品区伊人 | 69视频免费观看 | 国产精品手机在线 | 亚洲一级片在线观看 | 97福利| 色射网 | 国产99久一区二区三区a片 | 日韩成人午夜影院 | 欧美日韩精品一区二区三区 | 三级全黄做爰龚玥菲在线 | 丰满少妇中文字幕 | wwwxxx日韩 | 杨幂一区二区三区免费看视频 | 免费的一级黄色片 | 国产又爽又黄又嫩又猛又粗 | 国产一区二区三区视频免费在线观看 | 人妻视频一区 | 国产精品系列在线 | 五十路av在线 | 欧美黄色大片免费看 | 激情小说亚洲图片 | 免费涩涩 | 国产美女福利视频 | 不卡在线一区 | xxxx日本黄色| 日韩一区二区影院 | 国语av| 偷偷在线观看免费高清av | 先锋资源av | 欧美黄色录像 | 麻豆影视在线免费观看 | 久久七| 国产欧美一区二区三区精华液好吗 | 日b在线观看 | 欧美日韩丝袜 | 岛国大片在线免费观看 | 欧美一区二区三区成人 | 欧美亚洲国产精品 | 精品久久久999 | 青青国产| 人妻少妇偷人精品久久性色 | 荷兰女人裸体性做爰 | 人妻互换一二三区激情视频 | 粉嫩精品久久99综合一区 | 亚日韩一区| 欧美黄色小说视频 | 欧美日比视频 | 国产一线二线三线女 | 国产一区二区自拍 | 国产精品视频麻豆 | 久久6视频 | 少妇高潮久久久久久潘金莲 | 国产情侣久久 | 国产区亚洲区 | 国产精品96久久久久久 | 久久久久亚洲AV成人无在 | 国产又色又爽无遮挡免费 | 日本免费三片在线播放 | 国产一区在线免费观看 | 午夜视频在线观看免费视频 | 婷婷激情五月 | 性――交――性――乱a | 日韩av一| 国产精品色网 | 国产第一草草影院 | 丰满少妇在线观看网站 | 侵犯女教师一区二区三区 | 四虎黄色影院 | 成人av日韩 | 欧美大屁股熟妇bbbbbb | 国产一区美女 | 美女一级黄 | 国产成人无码专区 | 经典毛片 | 综合婷婷久久 | 91精品国产99久久久久久红楼 | 极品色综合| 久久精品视频免费看 | 法国空姐在线观看免费 | 91麻豆产精品久久久久久夏晴子 | 99re6在线观看 | 免费成人黄 | 久久手机免费视频 | 美女啪啪av | 中国特级黄色片 | 精品1区2区 | 成人深夜福利 | jizz韩国| 黑鬼大战白妞高潮喷白浆 | 老司机深夜福利视频 | 日日麻批 | 日韩一区二区高清视频 | 中文精品一区二区三区 | 激情国产 | 欧美激情aaa |