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

          37. 反引號的妙用:結構體里的 Tag 標簽

          共 3054字,需瀏覽 7分鐘

           ·

          2020-07-28 17:24

          點擊上方“Go編程時光”,選擇“加為星標

          第一時間關注Go技術干貨!




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

          正常情況下,你定義的結構體是這樣子的,每個字段都由名字和字段類型組成

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

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

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

          那么這個標簽有什么用呢?

          這邊先以 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,就不會打印了
          ????fmt.Printf("%s\n",?data1)

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

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

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

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

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

          因此運行后,輸出的結果如下

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

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

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

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

          定義完后,如何從結構體中,取出 Tag 呢?

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

          獲取 Tag 可以分為三個步驟:

          1. 獲取字段 field

          2. 獲取標簽 tag

          3. 獲取鍵值對 key:value

          演示如下

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

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

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

          獲取鍵值對,有Get 和 Lookup 兩種方法,但其實 Get 只是對 Lookup 函數(shù)的簡單封裝而已,當沒有獲取到對應 tag 的內容,會返回空字符串。

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

          空 Tag 和不設置 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. 實戰(zhàn)一下:利用 Tag 搞點事情?

          學會了如何定義 tag 和 獲取 tag,可以試著利用 ?tag 來做一些事情,來練習一下。

          這邊我舉個例子吧。

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

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

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

          Print(person)

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

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

          那該怎么做呢?

          先改造下 Person 結構體,給每個字段加上 tag 標簽,三個字段的tag 都有 label 屬性,而 Gender 多了一個 default 屬性,意在指定默認值。

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

          然后來寫一下這個 ?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?==?""?{
          ????????????//?如果沒有指定值,則用默認值替代
          ????????????value?=?defaultValue
          ????????}

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

          ????return?nil
          }

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

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

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




          明哥原創(chuàng)文都已傳至 Github:https://github.com/iswbm/GolangCodingTime

          本文永久博客鏈接:http://golang.iswbm.com/en/latest/c02/c02_10.html


          留言糾錯


          由于這個號,沒有留言功能,文章中不可避免(盡管我已經盡力驗證充分)會出現(xiàn)一些小毛病。

          為了避免文章因我個人語言表達不當,或者個人理解有誤,而誤導初學者,請大家共同監(jiān)督,若文章有說的不對的地方,請在下方鏈接里留言,幫我指正。謝謝大家,共同努力。Fighting

          “找茬”,”糾錯“,請來這里留言!


          喜歡本教程系列的同學
          歡迎長按下圖訂閱!

          ???




          瀏覽 50
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  一级A片调教打屁股 | 国产操逼电影大全 | 黄色小电影免费看 | 狠狠撸综合网 | 久久精品视频观看 |