<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 語言的反射機制

          共 2699字,需瀏覽 6分鐘

           ·

          2021-05-03 19:27

          因為沒有強類型語言的經(jīng)驗,反射這個概念,之前確實沒怎么接觸過。在維基百科上搜了一下,具體解釋如下:

          在計算機學中,反射式編程(英語:reflective programming)或反射(英語:reflection),是指計算機程序在運行時(runtime)可以訪問、檢測和修改它本身狀態(tài)或行為的一種能力。用比喻來說,反射就是程序在運行的時候能夠“觀察”并且修改自己的行為。

          go 中的反射也是這種作用,可以在程序運行期間,獲取變量的類型與值的信息,然后進行訪問或或者修改。go 語言中,內(nèi)置了 reflect 包,用來獲取一個變量的類型(type)與值(value),對應的方法分別為 reflect.TypeOf()reflect.ValueOf()

          反射類型

          TypeOf 方法,會返回該變量的類型對象,類型對象下可以獲取到變量的類型與種類。

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

          func?main()?{
          ?//?定義一個int類型的變量
          ?var?i?int?=?1
          ?//?獲取變量的類型對象
          ?var?typeOfNum?=?reflect.TypeOf(i)?

          ??//?輸出類型與種類
          ??typeOfNumName?=?typeOfNum.Name()
          ??typeOfNumKind?=?typeOfNum.Kind()
          ??fmt.Printf("name:?%s,?kind:?%s",?typeOfNumName,?typeOfNumKind)
          }

          可以看到,此時的類型與種類都為 int

          97d4c2de7d5979c80ec3542137e3ebcc.webp

          類型與種類

          類型表示定義變量的時候指定的類型,可以反映 type 關鍵字定義的類型,而種類是變量最終歸屬的類型。說起來可能比較蒼白,我們直接上代碼。

          type?num?int

          //?定義一個num類型的變量
          var?i?num?=?1
          var?typeOfNum?=?reflect.TypeOf(i)?

          可以看到,此時的類型為 num,種類為 int

          d87ed61a1caccb7305f93df89d90b99b.webp

          對于一些引用類型的變量,比如切片、函數(shù)、結(jié)構(gòu)體,kind 都能準確反映其底層的類型。

          func?printTypeOf(typeOf?reflect.Type)?{
          ?fmt.Printf("name:?%s,?kind:?%s\n",?typeOf.Name(),?typeOf.Kind())
          }

          type?Person?struct?{}
          type?IntSlice?[]int
          func?main()?{
          ?var?a?=?IntSlice{}
          ?var?b?=?Person{}
          ?printTypeOf(reflect.TypeOf(a))
          ?printTypeOf(reflect.TypeOf(b))
          }
          a1ebb03fe6b2c583aac3bfb73dc867fa.webp

          而面對匿名結(jié)構(gòu)體或者匿名函數(shù),其類型值會返回為空。

          func?main()?{
          ?var?a?=?struct?{}{}
          ?printTypeOf(reflect.TypeOf(a))
          }
          5fdd13a23cf503bcc6a49cb28a084d86.webp

          反射值

          ValueOf 方法,可以獲取一個變量的值。

          var?i?=?3.1415926
          var?s?=?"歡迎關注我的公眾號:『自然醒的筆記本』"

          fmt.Println(reflect.ValueOf(s))
          fmt.Println(reflect.ValueOf(i))
          20d6cff567e984d47dc5835deb8bedfe.webp

          通過反射的值對象,也能取到變量的種類,并且還能根據(jù)其種類,調(diào)用對應的方法獲取變量的真實值。

          var?i?=?100
          var?v?=?reflect.ValueOf(i)

          fmt.Println(v.Int())?//?如果值是?Int?類型,可以通過?Int?方法獲取具體值
          fmt.Println(v.Kind())
          02cba510b44a5c4b8fd197f68d43a3b5.webp

          修改值

          通過反射得到的值對象,可以對變量本身的值進行修改。首先,在獲取反射值時,不能直接獲取變量的反射值,而是要先取其指針的值對象。

          var?i?=?100
          var?v?=?reflect.ValueOf(&i)?//?取出變量i的指針的值對象

          fmt.Println(v.Kind(),?v)

          取出指針的值對象之后,不能立即賦值,因為此時拿到的是變量的地址。

          8c5e14b87cc6830da3b2600accc259c0.webp

          要賦值的話,需要先調(diào)用 Elem 方法,取出具體元素,然后進行賦值。

          var?i?=?100
          var?v?=?reflect.ValueOf(&i)?//?取出變量i的指針的值對象

          var?e?=?v.Elem()
          e.SetInt(500)?//?修改元素值

          fmt.Println(e.Kind(),?i)
          9a0dfcfa41453b4884eb9bfbe5c2bf38.webp

          值對象與結(jié)構(gòu)體

          前面介紹過,通過反射可以得到變量的值,對于結(jié)構(gòu)體來說,也是一樣。

          type?Person?struct?{
          ?name?string
          ?age?int
          ?gender?string
          ?address?string
          }

          var?p?=?Person{"Shenfq",?25,?"男",?"湖南長沙"}
          var?v?=?reflect.ValueOf(p)

          fmt.Println(v.Kind(),?v)
          9bd1a294cf33cb1cd2901be38db4004f.webp

          反射值對象還提供了一些方法,專門用來針對結(jié)構(gòu)體成員的信息獲取。

          NumField()

          NumField() 可以獲取結(jié)構(gòu)體成員的具體數(shù)量。

          var?p?=?Person{"Shenfq",?25,?"男",?"湖南長沙"}
          var?v?=?reflect.ValueOf(p)

          fmt.Println("Person?結(jié)構(gòu)體成員數(shù):",?v.NumField())
          520af3e98b1ff540c251a1792de6efe5.webp

          Field()

          Field() 可以獲取結(jié)構(gòu)體指定索引位置的成員的反射值。

          var?p?=?Person{"Shenfq",?25,?"男",?"湖南長沙"}
          var?v?=?reflect.ValueOf(p)
          var?num?=?v.NumField()
          for?i?:=0;?i?<?num;?i++?{
          ??var?val?=?v.Field(i)
          ??fmt.Printf("Person[%d]:?%s?%v\n",?i,?val.Type(),?val)
          }
          f4756df8b53a88e33ba5098fe0a3883e.webp

          FieldByName()

          FieldByName() 可以獲取結(jié)構(gòu)體指定成員名稱的成員的反射值。

          var?p?=?Person{"Shenfq",?25,?"男",?"湖南長沙"}
          var?v?=?reflect.ValueOf(p)
          var?vOfName?=?v.FieldByName("name")
          fmt.Printf("Person[name]:?%s?%v\n",?vOfName.Type(),?vOfName)
          6d25aab5ce9e6d025310506daf7fb79b.webp- END -


          瀏覽 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>
                  草比视频网 | 毛片毛片毛片毛片 | 天天狠操| 天天色啪 | 日韩在线黄色操B视频 |