<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go 語言中結(jié)構(gòu)體打 Tag 是什么意思?

          共 3226字,需瀏覽 7分鐘

           ·

          2021-11-23 12:17

          前言

          哈嘍,大家好,我是asong。今天想與大家分享Go語言中結(jié)構(gòu)體標(biāo)簽是怎么使用的,以及怎樣定制自己的結(jié)構(gòu)體標(biāo)簽解析。

          大多數(shù)初學(xué)者在看公司的項目代碼時,看到的一些結(jié)構(gòu)體定義會是這樣的:

          type?Location?struct?{
          ?Longitude?float32?`json:"lon,omitempty"`
          ?Latitude??float32?`json:"lat,omitempty"`
          }

          字段后面會有一個標(biāo)簽,這個標(biāo)簽有什么用呢?

          上面的例子中,標(biāo)簽json:"lon,omitempty"代表的意思是結(jié)構(gòu)體字段的值編碼為json對象時,每一個導(dǎo)出字段變成該對象的一個成員,這個成員的名字為lon或者lat,并且當(dāng)字段是空值時,不導(dǎo)出該字段;總結(jié)就是lon、lat是重命名成員的名字,omitempty用來決定成員是否導(dǎo)出。

          看到這里,有一些朋友可能會好奇,這個你是怎么知道這樣使用的呢?我可以隨便寫標(biāo)簽嗎?

          接下來我們就一點(diǎn)點(diǎn)來揭秘,開車?。?!

          什么是標(biāo)簽

          Go語言提供了可通過反射發(fā)現(xiàn)的的結(jié)構(gòu)體標(biāo)簽,這些在標(biāo)準(zhǔn)庫json/xml中得到了廣泛的使用,orm框架也支持了結(jié)構(gòu)體標(biāo)簽,上面那個例子的使用就是因為encoding/json支持了結(jié)構(gòu)體標(biāo)簽,不過他有自己的標(biāo)簽規(guī)則;但是他們都有一個總體規(guī)則,這個規(guī)則是不能更改的,具體格式如下:

          `key1:"value1"?key2:"value2"?key3:"value3"...`??//?鍵值對用空格分隔

          結(jié)構(gòu)體標(biāo)簽可以有多個鍵值對,鍵與值要用冒號分隔,值要使用雙引號括起來,多個鍵值對之間要使用一個空格分隔,千萬不要使用逗號?。。?/p>

          如果我們想要在一個值中傳遞多個信息怎么辦?不同庫中實現(xiàn)的是不一樣的,在encoding/json中,多值使用逗號分隔:

          `json:"lon,omitempty"`

          gorm中,多值使用分號分隔:

          `gorm:"column:id;primaryKey"

          具體使用什么符號分隔需要大家要看各自庫的文檔獲取。

          結(jié)構(gòu)體標(biāo)簽是在編譯階段就和成員進(jìn)行關(guān)聯(lián)的,以字符串的形式進(jìn)行關(guān)聯(lián),在運(yùn)行階段可以通過反射讀取出來。

          現(xiàn)在大家已經(jīng)知道什么是結(jié)構(gòu)體標(biāo)簽了,規(guī)則還是很規(guī)范的,但是很容易出錯,因為Go語言在編譯階段并不會對其格式做合法鍵值對的檢查,這樣我們不小心寫錯了,就很難被發(fā)現(xiàn),不過我們有go vet工具做檢查,具體使用來看一個例子:

          type?User?struct?{
          ?Name?string?`abc?def?ghk`
          ?Age?uint16?`123:?232`
          }
          func?main()??{
          }

          然后執(zhí)行go vet main.go,得出執(zhí)行結(jié)果:

          #?command-line-arguments
          go_vet_tag/main.go:4:2:?struct?field?tag?`abc?def?ghk`?not?compatible?with?reflect.StructTag.Get:?bad?syntax?for?struct?tag?pair
          go_vet_tag/main.go:5:2:?struct?field?tag?`123:?232`?not?compatible?with?reflect.StructTag.Get:?bad?syntax?for?struct?tag?value

          bad syntax for struct tag pair告訴我們鍵值對語法錯誤,bad syntax for struct tag value值語法錯誤。

          所以在我們項目中引入go vet作為CI檢查是很有必要的。

          標(biāo)簽使用場景

          Go官方已經(jīng)幫忙整理了哪些庫已經(jīng)支持了struct tag:https://github.com/golang/go/wiki/Well-known-struct-tags。

          TagDocumentation
          xmlhttps://godoc.org/encoding/xml
          jsonhttps://godoc.org/encoding/json
          asn1https://godoc.org/encoding/asn1
          reformhttps://godoc.org/gopkg.in/reform.v1
          dynamodbhttps://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/dynamodbattribute/#Marshal
          bigqueryhttps://godoc.org/cloud.google.com/go/bigquery
          datastorehttps://godoc.org/cloud.google.com/go/datastore
          spannerhttps://godoc.org/cloud.google.com/go/spanner
          bsonhttps://godoc.org/labix.org/v2/mgo/bson, https://godoc.org/go.mongodb.org/mongo-driver/bson/bsoncodec
          gormhttps://godoc.org/github.com/jinzhu/gorm
          yamlhttps://godoc.org/gopkg.in/yaml.v2
          tomlhttps://godoc.org/github.com/pelletier/go-toml
          validatehttps://github.com/go-playground/validator
          mapstructurehttps://godoc.org/github.com/mitchellh/mapstructure
          parserhttps://godoc.org/github.com/alecthomas/participle
          protobufhttps://github.com/golang/protobuf
          dbhttps://github.com/jmoiron/sqlx
          urlhttps://github.com/google/go-querystring
          featurehttps://github.com/nikolaydubina/go-featureprocessing

          json、yaml、gorm、validate、mapstructure、protobuf這幾個庫的結(jié)構(gòu)體標(biāo)簽是很常用的,gin框架就集成了validate庫用來做參數(shù)校驗,方便了許多,之前寫了一篇關(guān)于validate的文章:boss: 這小子還不會使用validator庫進(jìn)行數(shù)據(jù)校驗,開了~~~,可以關(guān)注一下。

          具體這些庫中是怎么使用的,大家可以看官方文檔介紹,寫的都很詳細(xì),具體場景具體使用哈?。?!

          自定義結(jié)構(gòu)體標(biāo)簽

          現(xiàn)在我們可以回答開頭的一個問題了,結(jié)構(gòu)體標(biāo)簽是可以隨意寫的,只要符合語法規(guī)則,任意寫都可以的,但是一些庫沒有支持該標(biāo)簽的情況下,隨意寫的標(biāo)簽是沒有任何意義的,如果想要我們的標(biāo)簽變得有意義,就需要我們提供解析方法。可以通過反射的方式獲取標(biāo)簽,所以我們就來看一個例子,如何使用反射獲取到自定義的結(jié)構(gòu)體標(biāo)簽。

          type?User?struct?{
          ?Name?string?`asong:"Username"`
          ?Age??uint16?`asong:"age"`
          ?Password?string?`asong:"min=6,max=10"`
          }
          func?getTag(u?User)?{
          ?t?:=?reflect.TypeOf(u)

          ?for?i?:=?0;?i???field?:=?t.Field(i)
          ??tag?:=?field.Tag.Get("asong")
          ??fmt.Println("get?tag?is?",?tag)
          ?}
          }

          func?main()??{
          ?u?:=?User{
          ??Name:?"asong",
          ??Age:?5,
          ??Password:?"123456",
          ?}
          ?getTag(u)
          }

          運(yùn)行結(jié)果如下:

          get?tag?is??Username
          get?tag?is??age
          get?tag?is??min=6,max=10

          這里我們使用TypeOf方法獲取的結(jié)構(gòu)體類型,然后去遍歷字段,每個字段StructField都有成員變量Tag

          //?A?StructField?describes?a?single?field?in?a?struct.
          type?StructField?struct?{
          ?Name?string
          ?PkgPath?string
          ?Type??????Type??????//?field?type
          ?Tag???????StructTag?//?field?tag?string
          ?Offset????uintptr???//?offset?within?struct,?in?bytes
          ?Index?????[]int?????//?index?sequence?for?Type.FieldByIndex
          ?Anonymous?bool??????//?is?an?embedded?field
          }

          Tag是一個內(nèi)置類型,提供了Get、Loopup兩種方法來解析標(biāo)簽中的值并返回指定鍵的值:

          func?(tag?StructTag)?Get(key?string)?string
          func?(tag?StructTag)?Lookup(key?string)?(value?string,?ok?bool)

          Get內(nèi)部也是調(diào)用的Lookup方法。區(qū)別在于Lookup會通過返回值告知給定key是否存在與標(biāo)簽中,Get方法完全忽略了這個判斷。

          總結(jié)

          本文主要介紹一下Go語言中的結(jié)構(gòu)體標(biāo)簽是什么,以及如何使用反射獲取到解結(jié)構(gòu)體標(biāo)簽,在日常開發(fā)中我們更多的是使用一些庫提供好的標(biāo)簽,很少自己開發(fā)使用,不過大家有興趣的話可以讀一下validae的源碼,看看他是如何解析結(jié)構(gòu)體中的tag,也可以自己動手實現(xiàn)一個校驗庫,當(dāng)作練手項目。

          文中代碼已上傳github:https://github.com/asong2020/Golang_Dream/tree/master/code_demo/struct_tag_demo

          好啦,本文到這里就結(jié)束了,我是asong,我們下期見。創(chuàng)建了讀者交流群,歡迎各位大佬們踴躍入群,一起學(xué)習(xí)交流。入群方式:關(guān)注公眾號獲取。更多學(xué)習(xí)資料請到公眾號領(lǐng)取。

          瀏覽 100
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人精品操BB视频 | 逼视频在线观看 | 人人射人人操人人舔 | 最新中文字幕在线免费观看 | 欧美老妇性爱乱伦 |