<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 面向?qū)ο缶幊唐ㄆ撸侯愋蛿嘌?/h1>

          共 9486字,需瀏覽 19分鐘

           ·

          2021-03-07 14:50

          在 Java、PHP 等語言的面向?qū)ο缶幊虒?shí)現(xiàn)中,提供了 instanceof 關(guān)鍵字來進(jìn)行接口和類型的斷言,這種斷言其實(shí)就是判定一個(gè)對(duì)象是否是某個(gè)類(包括父類)或接口的實(shí)例。

          Go 語言設(shè)計(jì)地非常簡(jiǎn)單,所以沒有提供類似的關(guān)鍵字,而是通過類型斷言運(yùn)算符 .(type) 來實(shí)現(xiàn),其中 type 對(duì)應(yīng)的就是要斷言的類型。下面,我們來看下具體的使用示例。

          一、接口類型斷言

          首先來看接口類型斷言。

          上篇教程介紹的 Number 類、Number1Number2 接口為例,在 Go 語言中,要斷言 Number2 接口類型實(shí)例 num2 是否也是 Number1 接口類型(即 num2 是否實(shí)現(xiàn)了 Number1 接口,本質(zhì)上則是 num1 是否實(shí)現(xiàn)了 Number1 接口),可以這么做:

          var num1 Number = 1;
          var num2 Number2 = &amp;num1;
          if num3, ok := num2.(Number1); ok {
              fmt.Println(num3.Equal(1))
          }

          我們通過 num2.(Number1) 這個(gè)表達(dá)式斷言 num2 是否是 Number1 類型的實(shí)例,如果是,ok 值為 true,然后執(zhí)行 if 語句塊中的代碼;否則 ok 值為 false,不執(zhí)行 if 語句塊中的代碼。

          需要注意的是,類型斷言是否成功要在運(yùn)行期才能夠確定,它不像接口賦值,編譯器只需要通過靜態(tài)類型檢查即可判斷賦值是否可行。

          二、結(jié)構(gòu)體類型斷言

          接下來我們來看下結(jié)構(gòu)體類型斷言。

          結(jié)構(gòu)體類型斷言實(shí)現(xiàn)語法和接口類型斷言一樣,我們以前面包的可見性教程中定義的 Animal、Dog 類為例,它們都位于 animal 包中,由于類型斷言語法 . 左側(cè)的變量類型必須是接口類型,所以我們需要新增一個(gè) IAnimal 接口(首字母大寫的接口才能在包外可見,這一點(diǎn)和類名、方法名、函數(shù)名、變量名、屬性名一樣):

          type IAnimal interface {
              GetName() string
              Call() string
              FavorFood() string
          }

          這樣一來,AnimalDog 類就都實(shí)現(xiàn)了 IAnimal 接口,要查詢 IAnimal 接口類型的實(shí)例是否是 Dog 結(jié)構(gòu)體類型,可以這么做:

          var animal = NewAnimal("中華田園犬")
          var pet = NewPet("泰迪")
          var ianimal IAnimal = NewDog(&amp;animal, pet)
          if dog, ok := ianimal.(Dog); ok {
              fmt.Println(dog.GetName())
              fmt.Println(dog.Call())
              fmt.Println(dog.FavorFood())
          }

          如果 ianimal 變量是 Dog 類型,則 ok 值為 true,執(zhí)行 if 語句塊中的代碼;否則 ok 值為 false。

          需要注意的是,在 Go 語言結(jié)構(gòu)體類型斷言時(shí),子類的實(shí)例并不歸屬于父類,即使子類和父類屬性名和成員方法列表完全一致,因?yàn)轭惻c類之間的「繼承」是通過組合實(shí)現(xiàn)的,并不是 Java/PHP 中的那種父子繼承關(guān)系,這是新手需要注意的地方。同理,父類實(shí)現(xiàn)了某個(gè)接口,不代表組合類它的子類也實(shí)現(xiàn)了這個(gè)接口。

          比如,我們把上述代碼中的 ianimal.(Dog) 替換成 ianimal.(Animal),則查詢結(jié)果的 ok 值為 false。當(dāng)然,由于 Dog 實(shí)現(xiàn)了 IAnimal 接口,所以接口類型斷言 ianimal.(IAnimal) 也會(huì)成功,但是如果 Dog 沒有實(shí)現(xiàn)該接口,則斷言失敗,即使父類 Animal 實(shí)現(xiàn)了這個(gè)接口也不行。

          所以,學(xué)院君這里使用父子類來稱呼,完全是為了方便大家對(duì)比理解,實(shí)際上已經(jīng)和傳統(tǒng)的面向?qū)ο缶幊讨械母缸宇愅耆皇且粋€(gè)概念了,其本質(zhì)原因就是 Go 使用了組合而非繼承來構(gòu)建類與類之間的關(guān)聯(lián)和層次關(guān)系。

          三、基于反射動(dòng)態(tài)斷言類型

          此外,還可以基于反射在運(yùn)行時(shí)動(dòng)態(tài)進(jìn)行類型斷言,使用 reflect 包提供的 TypeOf 函數(shù)即可實(shí)現(xiàn)。正如我們?cè)?a target="_blank" textvalue="變長參數(shù)" data-itemshowtype="0" tab="innerlink" data-linktype="2">變長參數(shù)中演示的那樣:

          func myPrintf(args ...interface{}) {
              for _, arg := range args {
                  switch reflect.TypeOf(arg).Kind() {
                  case reflect.Int:
                      fmt.Println(arg, "is an int value.")
                  case reflect.String:
                      fmt.Printf("\"%s\" is a string value.\n", arg)
                  case reflect.Array:
                      fmt.Println(arg, "is an array type.")
                  default:
                      fmt.Println(arg, "is an unknown type.")
                  }
              }
          }

          因此,如果要獲取 ianimal 的實(shí)際類型,可以通過 reflect.TypeOf(ianimal) 獲?。?/p>

          var animal = NewAnimal("中華田園犬")
          var pet = NewPet("泰迪")
          var ianimal IAnimal = NewDog(&amp;animal, pet)
          fmt.Println(reflect.TypeOf(ianimal))

          返回的結(jié)果是 animal.Dog。

          對(duì)于基本數(shù)據(jù)類型,比如 int、string、bool 這些,不必通過反射,直接使用 variable.(type) 表達(dá)式即可獲取 variable 變量對(duì)應(yīng)的類型值:

          func myPrintf(args ...interface{}) {
              for _, arg := range args {
                  switch arg.(type) {
                  case int:
                      fmt.Println(arg, "is an int value.")
                  case string:
                      fmt.Printf("\"%s\" is a string value.\n", arg)
                  case bool:
                      fmt.Println(arg, "is a bool value.")
                  default:
                      fmt.Println(arg, "is an unknown type.")
                  }
              }
          }

          Go 語言 fmt 標(biāo)準(zhǔn)庫中的 Println() 函數(shù)底層就是基于類型斷言將傳入?yún)?shù)值轉(zhuǎn)化為字符串進(jìn)行打印的:

          func (p *pp) printArg(arg interface{}, verb rune) {
              p.arg = arg
              p.value = reflect.Value{}

              ...

              // Some types can be done without reflection.
              switch f := arg.(type) {
              case bool:
                  p.fmtBool(f, verb)
              case float32:
                  p.fmtFloat(float64(f), 32, verb)
              case float64:
                  p.fmtFloat(f, 64, verb)
              case complex64:
                  p.fmtComplex(complex128(f), 64, verb)
              case complex128:
                  p.fmtComplex(f, 128, verb)
              case int:
                  p.fmtInteger(uint64(f), signed, verb)
              case int8:
                  p.fmtInteger(uint64(f), signed, verb)
              case int16:
                  p.fmtInteger(uint64(f), signed, verb)
              case int32:
                  p.fmtInteger(uint64(f), signed, verb)
              case int64:
                  p.fmtInteger(uint64(f), signed, verb)
              case uint:
                  p.fmtInteger(uint64(f), unsigned, verb)
              case uint8:
                  p.fmtInteger(uint64(f), unsigned, verb)
              case uint16:
                  p.fmtInteger(uint64(f), unsigned, verb)
              case uint32:
                  p.fmtInteger(uint64(f), unsigned, verb)
              case uint64:
                  p.fmtInteger(f, unsigned, verb)
              case uintptr:
                  p.fmtInteger(uint64(f), unsigned, verb)
              case string:
                  p.fmtString(f, verb)
              case []byte:
                  p.fmtBytes(f, verb, "[]byte")
              case reflect.Value:
                  // Handle extractable values with special methods
                  // since printValue does not handle them at depth 0.
                  if f.IsValid() &amp;&amp; f.CanInterface() {
                      p.arg = f.Interface()
                      if p.handleMethods(verb) {
                          return
                      }
                  }
                  p.printValue(f, verb, 0)
              default:
                  // If the type is not simple, it might have methods.
                  if !p.handleMethods(verb) {
                      // Need to use reflection, since the type had no
                      // interface methods that could be used for formatting.
                      p.printValue(reflect.ValueOf(f), verb, 0)
                  }
              }
          }

          其中 arg 對(duì)應(yīng)的是外部傳入的每個(gè)待打印參數(shù)值。interface{} 表示空接口類型,在 Go 語言中,空接口可以表示任意類型,關(guān)于空接口以及它與反射結(jié)合來實(shí)現(xiàn)更復(fù)雜的類型功能,將是我們下篇教程重點(diǎn)探討的內(nèi)容。

          (本文完)


          學(xué)習(xí)過程中有任何問題,可以通過下面的評(píng)論功能或加入「Go 語言研習(xí)社」與學(xué)院君討論:


          本系列教程首發(fā)在 geekr.dev,你可以點(diǎn)擊頁面左下角閱讀原文鏈接查看最新更新的教程。

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

          手機(jī)掃一掃分享

          分享
          舉報(bào)

          評(píng)論
          圖片
          表情
          推薦
          <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>
                  亚洲精品无码视频 | www.豆花视频 | 天天插插综合视频综合 | 免费jlzzjlzz在线播放欧美 | 爽妇综合网 |