最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang中結(jié)構(gòu)體映射mapstructure庫深入詳解

 更新時間:2023年01月02日 11:27:17   作者:alwaysrun  
mapstructure用于將通用的map[string]interface{}解碼到對應(yīng)的 Go 結(jié)構(gòu)體中,或者執(zhí)行相反的操作。很多時候,解析來自多種源頭的數(shù)據(jù)流時,我們一般事先并不知道他們對應(yīng)的具體類型。只有讀取到一些字段之后才能做出判斷

在數(shù)據(jù)傳遞時,需要先編解碼;常用的方式是JSON編解碼(參見《golang之JSON處理》)。但有時卻需要讀取部分字段后,才能知道具體類型,此時就可借助mapstructure庫了。

mapstructure庫

mapstructure可方便地實(shí)現(xiàn)map[string]interface{}struct間的轉(zhuǎn)換;使用前,需要先導(dǎo)入庫:

go get github.com/mitchellh/mapstructure

字段標(biāo)簽

默認(rèn)情況下,mapstructure使用字段的名稱做匹配映射(即在map中以字段名為鍵值查找字段值);注意匹配時是忽略大小寫的。也可通過標(biāo)簽來設(shè)定字段映射名稱:

type Person struct {
  Name string `mapstructure:"userName"`
}

內(nèi)嵌結(jié)構(gòu)

go中結(jié)構(gòu)體是可以任意嵌套的;嵌套后即認(rèn)為擁有對應(yīng)的字段。但是,默認(rèn)情況下mapstructure只處理當(dāng)前結(jié)構(gòu)定義的字段,若要自動處理內(nèi)嵌字段需要添加標(biāo)簽squash

type Student struct {
  Person `mapstructure:",squash"`
  Age int 
}

未映射字段

若源數(shù)據(jù)中有未映射的值(即結(jié)構(gòu)體中無對應(yīng)的字段),mapstructure默認(rèn)會忽略它??梢栽诮Y(jié)構(gòu)體中定義一個特殊字段(類型為map[string]interface{},且標(biāo)簽要設(shè)置為mapstructure:",remain"),來存放所有未能映射的字段中。

type Student struct {
  Name  string
  Age   int
  Other map[string]interface{} `mapstructure:",remain"`
}

Metadata

mapstructure中可以使用Metadata收集一些解碼時會產(chǎn)生的有用信息。

// mapstructure.go
type Metadata struct {
  Keys   []string  // 解碼成功的鍵
  Unused []string  // 源數(shù)據(jù)中存在,但目標(biāo)結(jié)構(gòu)中不存在的鍵
  Unset  []string  // 未設(shè)定的(源數(shù)據(jù)中缺失的)鍵
}

為了獲取這些信息,需要使用DecodeMetadata來解碼:

  var metadata mapstructure.Metadata
  err := mapstructure.DecodeMetadata(m, &p, &metadata)

弱類型輸入

有時候,并不想對結(jié)構(gòu)體字段類型和map[string]interface{}的對應(yīng)鍵值做強(qiáng)類型一致的校驗(yàn)。這時可以使用WeakDecode/WeakDecodeMetadata方法,它們會嘗試做類型轉(zhuǎn)換:

  • 布爾轉(zhuǎn)字符串:true = “1”, false = “0”;
  • 布爾轉(zhuǎn)數(shù)字:true = 1, false = 0;
  • 數(shù)字轉(zhuǎn)布爾:true if value != 0;
  • 字符串轉(zhuǎn)布爾:可接受,
  • 真:1, t, T, TRUE, true, True
  • 假:0, f, F, FALSE, false, False
  • 數(shù)字轉(zhuǎn)字符串:自動base10轉(zhuǎn)換;
  • 負(fù)數(shù)轉(zhuǎn)為無符號數(shù)(上溢);
  • 字符串轉(zhuǎn)數(shù)字:根據(jù)前綴(如0x等)轉(zhuǎn)換;
  • 空數(shù)組與空map間互轉(zhuǎn);
  • 單個值轉(zhuǎn)為切片;

逆向轉(zhuǎn)換

除將map轉(zhuǎn)換為結(jié)構(gòu)體外,mapstructure也可以將結(jié)構(gòu)體反向解碼為map[string]interface{}。在反向解碼時,我們可以為某些字段設(shè)置mapstructure:“,omitempty”,當(dāng)這些字段為默認(rèn)值時,就不會出現(xiàn)在map中:

  p := &Student{
    Name: "Mike",
    Age:  12,
  }
  var m map[string]interface{}
  mapstructure.Decode(p, &m)

解碼器

mapstructure提供了解碼器(Decoder),可靈活方便地控制解碼:

type DecoderConfig struct {
    // 若設(shè)定,則在任何解碼或類型轉(zhuǎn)換(設(shè)定了WeaklyTypedInput)前調(diào)用;對于設(shè)定了squash的內(nèi)嵌字段,整體調(diào)用一次;若返回錯誤,則整個解碼失敗
    DecodeHook DecodeHookFunc
    // 若設(shè)定,則源數(shù)據(jù)中存在未使用字段時,報錯
    ErrorUnused bool
    // 若設(shè)定,則有字段未設(shè)定時,報錯
    ErrorUnset bool
    // 若設(shè)定,則在設(shè)定字段前先清空(對于map等類型會先清理掉舊數(shù)據(jù))
    ZeroFields bool
    // 若設(shè)定,支持若類型間的轉(zhuǎn)換
    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
}

一個支持弱類型轉(zhuǎn)換的示例:要獲取的結(jié)果放到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:%#v\n", metadata.Keys, metadata.Unused)
    } else {
        log.Println("decode fail:", err)
    }
}

示例

通過一個messageData結(jié)構(gòu),action會指示最終的data類型。接收到數(shù)據(jù)后,先解析出atcion,再根據(jù)action轉(zhuǎn)換為真實(shí)的類型。

因time.Time是一個結(jié)構(gòu)體(json序列化時會轉(zhuǎn)換為時間字符串),mapstructure無法正確處理,所以推薦使用時間戳。

為了能正確解析內(nèi)嵌的DataBasic,需要標(biāo)記為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)
}

到此這篇關(guān)于Golang中結(jié)構(gòu)體映射mapstructure庫深入詳解的文章就介紹到這了,更多相關(guān)Go mapstructure內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go構(gòu)建高性能的命令行工具使例詳解

    Go構(gòu)建高性能的命令行工具使例詳解

    這篇文章主要為大家介紹了Go構(gòu)建高性能的命令行工具使例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Go語言學(xué)習(xí)教程之goroutine和通道的示例詳解

    Go語言學(xué)習(xí)教程之goroutine和通道的示例詳解

    這篇文章主要通過A?Tour?of?Go中的例子進(jìn)行學(xué)習(xí),以此了解Go語言中的goroutine和通道,文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2022-09-09
  • Golang設(shè)計模式中的橋接模式詳細(xì)講解

    Golang設(shè)計模式中的橋接模式詳細(xì)講解

    橋接模式是一種結(jié)構(gòu)型設(shè)計模式,通過橋接模式可以將抽象部分和它的實(shí)現(xiàn)部分分離,本文主要介紹了GoLang橋接模式,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2023-01-01
  • Go語言讀取文件的方法小結(jié)

    Go語言讀取文件的方法小結(jié)

    寫程序時經(jīng)常需要從一個文件讀取數(shù)據(jù),然后輸出到另一個文件,這篇文章主要為大家詳細(xì)介紹了Go語言讀取文件的幾種方法,希望對大家有所幫助
    2024-01-01
  • golang內(nèi)存對齊詳解

    golang內(nèi)存對齊詳解

    在golang中,每一種數(shù)據(jù)類型都有其對應(yīng)的數(shù)據(jù)類型大小,也就是占用了多少內(nèi)存空間,我們可以通過unsafe.Sizeof函數(shù),來確定一個變量占用的內(nèi)存字節(jié)數(shù),本文將詳細(xì)給大家介紹golang內(nèi)存對齊,需要的朋友可以參考下
    2023-10-10
  • 深入解析Go template模板使用詳解

    深入解析Go template模板使用詳解

    這篇文章主要介紹了深入解析Go template模板使用詳解,需要的朋友可以參考下
    2022-04-04
  • 舉例講解Go語言中函數(shù)的閉包使用

    舉例講解Go語言中函數(shù)的閉包使用

    這篇文章主要介紹了Go語言中函數(shù)的閉包使用示例,函數(shù)閉包c(diǎn)losure是編程語言中十分重要的特性,需要的朋友可以參考下
    2016-03-03
  • Golang中調(diào)用deepseekr1的教程詳解

    Golang中調(diào)用deepseekr1的教程詳解

    這篇文章主要為大家詳細(xì)介紹了Golang中調(diào)用deepseekr1的相關(guān)教程,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,感興趣的小伙伴可以了解下
    2025-02-02
  • go 生成器模式的具體使用

    go 生成器模式的具體使用

    生成器是一種創(chuàng)建型設(shè)計模式,使你能夠分步驟創(chuàng)建復(fù)雜對象,本文主要介紹了go生成器模式的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Golang實(shí)現(xiàn)Md5校驗(yàn)的示例代碼

    Golang實(shí)現(xiàn)Md5校驗(yàn)的示例代碼

    本文主要介紹了Golang實(shí)現(xiàn)Md5校驗(yàn)的示例代碼,要求接收方需要文件的md5值,和接收到的文件做比對,以免文件不完整,但引起bug,下面就一起來解決一下
    2024-08-08

最新評論

宁夏| 红河县| 容城县| 永州市| 高淳县| 若羌县| 瑞昌市| 云梦县| 宁海县| 玉龙| 泸定县| 巨野县| 长治市| 广南县| 阳新县| 左云县| 兴文县| 如东县| 武功县| 青阳县| 宜君县| 桐乡市| 红河县| 阿城市| 绥滨县| 东乡| 安义县| 普兰店市| 特克斯县| 平昌县| 东城区| 鱼台县| 北票市| 郁南县| 阿鲁科尔沁旗| 博湖县| 开原市| 上林县| 通海县| 广河县| 长兴县|