<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>

          2020重學(xué)Go系列:37. 反引號(hào)的妙用—結(jié)構(gòu)體里的 Tag 標(biāo)簽

          共 3020字,需瀏覽 7分鐘

           ·

          2020-07-27 19:48



          1. 拋磚引玉:什么是 Tag?

          正常情況下,你定義的結(jié)構(gòu)體是這樣子的,每個(gè)字段都由名字和字段類型組成

          type?Person?struct?{
          ????Name?string?
          ????Age??int???
          ????Addr?string
          }

          也有例外,就像下面這樣子,字段上還可以額外再加一個(gè)屬性,用反引號(hào)(Esc鍵下面的那個(gè)鍵)包含的字符串,稱之為 Tag,也就是標(biāo)簽。

          type?Person?struct?{
          ????Name?string?`json:"name"`
          ????Age??int????`json:"age"`
          ????Addr?string?`json:"addr,omitempty"`
          }

          那么這個(gè)標(biāo)簽有什么用呢?

          這邊先以 encoding/json 庫的用法拋磚引玉,看一下它能起到什么樣的效果。

          package?main

          import?(
          ????"encoding/json"
          ????"fmt"
          )

          type?Person?struct?{
          ????Name?string?`json:"name"`
          ????Age??int????`json:"age"`
          ????Addr?string?`json:"addr,omitempty"`
          }

          func?main()?{
          ????p1?:=?Person{
          ????????Name:?"Jack",
          ????????Age:??22,
          ????}

          ????data1,?err?:=?json.Marshal(p1)
          ????if?err?!=?nil?{
          ????????panic(err)
          ????}

          ????//?p1?沒有?Addr,就不會(huì)打印了
          ????fmt.Printf("%s\n",?data1)

          ????//?================

          ????p2?:=?Person{
          ????????Name:?"Jack",
          ????????Age:??22,
          ????????Addr:?"China",
          ????}

          ????data2,?err?:=?json.Marshal(p2)
          ????if?err?!=?nil?{
          ????????panic(err)
          ????}

          ????//?p2?則會(huì)打印所有
          ????fmt.Printf("%s\n",?data2)
          }

          由于 Person 結(jié)構(gòu)體里的 Addr 字段有 omitempty 屬性,因此 encoding/json 在將對(duì)象轉(zhuǎn)化 json 字符串時(shí),只要發(fā)現(xiàn)對(duì)象里的 Addr 為 ?false, 0, 空指針,空接口,空數(shù)組,空切片,空映射,空字符串中的一種,就會(huì)被忽略。

          因此運(yùn)行后,輸出的結(jié)果如下

          $?go?run?demo.go?
          {"name":"Jack","age":22}
          {"name":"Jack","age":22,"addr":"China"}

          2. 不懂就問:如何定義獲取 Tag ?

          Tag 由反引號(hào)包含,由一對(duì)或幾對(duì)的鍵值對(duì)組成,通過空格來分割鍵值。格式如下

          `key01:"value01"?key02:"value02"?key03:"value03"`

          定義完后,如何從結(jié)構(gòu)體中,取出 Tag 呢?

          答案就是,我們上一節(jié)學(xué)過的 "反射"。

          獲取 Tag 可以分為三個(gè)步驟:

          1. 獲取字段 field

          2. 獲取標(biāo)簽 tag

          3. 獲取鍵值對(duì) key:value

          演示如下

          //?三種獲取?field
          field?:=?reflect.TypeOf(obj).FieldByName("Name")
          field?:=?reflect.ValueOf(obj).Type().Field(i)??//?i?表示第幾個(gè)字段
          field?:=?reflect.ValueOf(&obj).Elem().Type().Field(i)??//?i?表示第幾個(gè)字段

          //?獲取?Tag
          tag?:=?field.Tag?

          //?獲取鍵值對(duì)
          labelValue?:=?tag.Get("label")
          labelValue,ok?:=?tag.Lookup("label")

          獲取鍵值對(duì),有Get 和 Lookup 兩種方法,但其實(shí) Get 只是對(duì) Lookup 函數(shù)的簡單封裝而已,當(dāng)沒有獲取到對(duì)應(yīng) tag 的內(nèi)容,會(huì)返回空字符串。

          func?(tag?StructTag)?Get(key?string)?string?{
          ????v,?_?:=?tag.Lookup(key)
          ????return?v
          }

          空 Tag 和不設(shè)置 Tag 效果是一樣的

          package?main

          import?(
          ????"fmt"
          ????"reflect"
          )

          type?Person?struct?{
          ????Name?string?``
          ????Age?string
          }
          func?main()?{
          ????p?:=?reflect.TypeOf(Person{})
          ????name,?_?:=?p.FieldByName("Name")
          ????fmt.Printf("%q\n",?name.Tag)?//輸出?""
          ????age,?_?:=?p.FieldByName("Age")
          ????fmt.Printf("%q\n",?age.Tag)?//?輸出?""
          }

          3. 實(shí)戰(zhàn)一下:利用 Tag 搞點(diǎn)事情?

          學(xué)會(huì)了如何定義 tag 和 獲取 tag,可以試著利用 ?tag 來做一些事情,來練習(xí)一下。

          這邊我舉個(gè)例子吧。

          如果我想實(shí)現(xiàn)一個(gè)函數(shù)(就叫 Print 吧),在打印 person 對(duì)象時(shí),能夠美化輸出

          type?Person?struct?{
          ????Name????????string?
          ????Age?????????int????
          ????Gender??????string
          }

          person?:=?Person{
          ????Name:????????"MING",
          ????Age:?????????29,
          }

          Print(person)

          就像下面這樣,key 和 value 之間有個(gè) is:,如果沒有指定 Gender 的值,那么顯示為unknown(未知)。

          Name?is:?MING
          Age?is:?29
          Gender?is:?unknown

          那該怎么做呢?

          先改造下 Person 結(jié)構(gòu)體,給每個(gè)字段加上 tag 標(biāo)簽,三個(gè)字段的tag 都有 label 屬性,而 Gender 多了一個(gè) default 屬性,意在指定默認(rèn)值。

          type?Person?struct?{
          ????Name????????string?`label:"Name?is:?"`
          ????Age?????????int????`label:"Age?is:?"`
          ????Gender??????string?`label:"Gender?is:?"?default:"unknown"`
          }

          然后來寫一下這個(gè) ?Print 函數(shù)

          func?Print(obj?interface{})?error?{
          ????//?取?Value
          ????v?:=?reflect.ValueOf(obj)

          ????//?解析字段
          ????for?i?:=?0;?i?
          ????????//?取tag
          ????????field?:=?v.Type().Field(i)
          ????????tag?:=?field.Tag

          ????????//?解析label?和?default
          ????????label?:=?tag.Get("label")
          ????????defaultValue?:=?tag.Get("default")

          ????????value?:=?fmt.Sprintf("%v",?v.Field(i))
          ????????if?value?==?""?{
          ????????????//?如果沒有指定值,則用默認(rèn)值替代
          ????????????value?=?defaultValue
          ????????}

          ????????fmt.Println(label?+?value)
          ????}

          ????return?nil
          }

          最后執(zhí)行一下,看了下輸出,符合我們的預(yù)期:

          $?go?run?demo.go?
          Name?is:?MING
          Age?is:?29
          Gender?is:?unknown

          至此,我們就把 Tag 的用法介紹完了。




          推薦閱讀



          學(xué)習(xí)交流 Go 語言,掃碼回復(fù)「進(jìn)群」即可


          站長 polarisxu

          自己的原創(chuàng)文章

          不限于 Go 技術(shù)

          職場(chǎng)和創(chuàng)業(yè)經(jīng)驗(yàn)


          Go語言中文網(wǎng)

          每天為你

          分享 Go 知識(shí)

          Go愛好者值得關(guān)注


          瀏覽 34
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  日本va在线观看 日本va中文字幕 | 大鸡吧日逼网站 | 国产亚洲免费视频在线观看 | 国产一级a爱做片免费☆观看 | 天天看 天天干 |