【Go語言】【14】GO語言的接口類型

一、什麼是接口?
編程

在面向對象的語言中,接口用來限制實現類行爲的。怎麼理解這句話呢?設計模式


定義一個Person接口,我只會站在個人角度上考慮問題,好比Person(人),天然想到會吃飯、睡覺等:數組

interface Person編程語言

{ide

      // 人會吃飯函數

      void eat();測試


      // 人會睡覺ui

      void sleep();spa

}設計


我是站在接口角度上考慮接口如何定義,此時不會過多考慮實現類的行爲。

這很正常,由於我不能肯定誰會使用個人接口,有一天SuperMan說:「我要用你定義的接口」,那SuperMan必須用implements實現Person接口的行爲:

// SuperMan實現Person接口

public class SuperMan implements Person

{

      // 超人會吃飯

       public void eat()

       {

              System.out.println("super man can eat.");

       }


       // 超人會睡覺

       public void sleep()

       {

              System.out.println("super man can sleep.");

       }

}


等到SuperMan實現完了以後,他對我說:「做爲超人,我是會飛的哦~」

這時做爲Person定義者的我,只有兩個選擇:

  • 對SuperMan說:「飛是你本身的行爲,我不幫你定義這種行爲!」。但是通過若干萬年以後人類進化了怎麼辦?

  • 對SuperMan說:「好吧,我幫你定義這種行爲,但是一旦Person有了fly,你也必須實現fly」

其實不管上面哪一種結果,都至關於接口把實現類綁架了。


【備註】:悄悄地告訴你,上面的代碼是Java語言                                                                                                      



二、GO語言的接口呢?

GO語言有接口類型interface{}),它與面向對象的接口含義不一樣,GO語言的接口類型與數組(array)、切片(slice)、集合(map)、結構體(struct)是同等地位的。怎麼理解這句話呢?

咱們前面已知道:

var num int  // 定義了一個int型變量num

同理:

var any interface{} // 定義了一個接口類型變量any

從這個角度上看,GO的interface{}與面向對象的接口是不同吧。C_0009.gif   更加不同的是,interface{}是一個任意類型,或者說是萬能類型。


三、GO語言的任意類型

也就是說定義一個變量爲interface{}類型,能夠把任意的值賦給這個變量,例如:

var v1 interface{} = 250       // 把int值賦給interface{}

var v2 interface{} = "eagle" // 把string值賦給interface{}

var v3 interface{} = &v1      // 把v1的地址賦給interface{}

固然函數的入參類型也能夠是interface{},這樣函數就能夠接受任意類型的參數,例如GO語言標準庫fmt中的函數Println()

func Println(args ...interface{}){

        // 略

}


任意類型看起來很爽,能夠把任意的值都賦給interface{}類型變量,就像JDK1.4時的Vector,那時候Java尚未泛型的概念,任意值均可以向Vector裏面放,但問題也接踵而至:

// 定義一個長度爲3的Any類型數組,求數組元素之和,即anyArr[0]+anyArr[1]+anyArr[2]

var anyArr [3]interface{}

anyArr[0] = "eagle"    // anyArr[0]賦值爲字符串

anyArr[1] = 20           // anyArr[1]賦值爲int

anyArr[2] = 75.3        // anyArr[2]賦值爲float64

// 此時若求和,會有什麼結果呢?

fmt.Println(anyArr[0] + anyArr[1] + anyArr[2])


四、類型判斷

上例直觀上來看,string不能和int直接相加,因此咱們須要判斷元素類型,若元素類型是數字型的,咱們就執行「+」操做;若元素類型是字符串型的,咱們就跳過。這裏須要引入另一個知識:switch-type

即:拿到一個interface{}以後,能夠結合switch語句判斷變量的類型                                                                            

例如:

var v interface{} = 3

switch v.(type){

      case int:

              fmt.Println("3 is int")

      case string:

              fmt.Println("3 is string")

      default:

              fmt.Println("unkown type")

}

因此上面的例子能夠進一步修改以下:

// 定義一個長度爲3的Any類型數組,求數組元素之和,即anyArr[0]+anyArr[1]+anyArr[2]

var anyArr [3]interface{}

anyArr[0] = "eagle"

anyArr[1] = 20

anyArr[2] = 75.3


// 定義一個總和變量total

var total float64 = 0


// 遍歷Any類型數組

for i := 0; i < len(anyArr); i++ {

        // 針對Any類型數組中的每一個元素進行類型查詢

        switch vType := anyArr[i].(type) {

              case int:

                      total += float64(vType)

              case float64:

                      total += vType

              default:

                      // do nothing

        }

}


// 打印Any類型數組中數字之和

fmt.Println(total)


五、interface類型與struct類型

 從上面看interface類型很簡單嘛,或許吧。

咱們再回顧一下struct類型,struct類型是一個結構體,裏面能夠定義成員,它相似面向對象的一個類,類裏面能夠定義成員變量,好比:

// 定義一個person結構體,裏面有姓名、年齡、身高、體重成員

type person struct{

        name                 string

        age                    int

        height, weight   float64

}

那麼interface類型是否也能夠這樣定義呢?以下:

/**

 * 定義一個手錶接口,經過手錶接口咱們能夠知道小時、分鐘和秒

 */

type watch interface {

        getHour() int

        getMinute() int

        getSecond() int

}

經過編譯(go build myIf.go)會發現並無拋出錯誤!

wKiom1WlKLnStanZAADiDZWEgn0265.jpg

從結果能夠看出徹底能夠這樣定義一個類型爲interface的變量watch,而且還能夠爲watch增長相應的方法;但與struct不一樣的是:struct裏面的成員是變量,而interface裏面的成員是函數,即咱們可使用interface定義接口。


六、interface定義接口示例

(1)GO語言接口實現

       周圍的很多朋友如今都有一款iWatch智能手錶,通常都用來運動時監控心率,這也意味着iWatch不只能看時間這麼簡單。下面咱們定義一個iWatch類型:

type iWatch int    // 定義一個iWatch類型,它實際上就是int型;至關於爲int型取一個別名iWatch

接下來爲iWatch類型增長三個方法,分別爲getHour()、getMinute()、getSecond()

// 爲iWatch增長getHour()方法

func (w iWatch) getHour() int {

        return time.Now().Hour()

}


// 爲iWatch增長getMinute()方法

func (w iWatch) getMinute() int {

        return time.Now().Minute()

}


// 爲iWatch增長getSecond()方法

func (w iWatch) getSecond() int {

        return time.Now().Second()

}

下面是GO語言的精彩內容,請各位看客睜大眼睛:

func main() {

        var w watch  // 定義類型爲watch的變量w

        var t iWatch  // 定義類型爲iWatch的變量t

        w = t             // 把類型爲watch的變量w賦值給類型爲iWatch的變量t,這樣能行的通嗎?

        fmt.Println("Current Hour:", w.getHour(), ", Minute:", w.getMinute(), ", Second:", w.getSecond())

}

在這個測試代碼中:

var w watch

至關於定義了一個接口變量

var t iWatch

至關於定義了一個iWatch對象

w = t

直接把對象t 賦給了接口變量w,但沒有像其它面嚮對象語言那樣,讓iWatch implements watch,這樣能行的通嗎?

把「嗎」字去掉,請看結果:

wKioL1WmVRujSREcAAB1baVrR5Y574.jpg

神奇吧 :)

以上是GO語言的接口實現。


(2)Java語言的接口實現

用面向對象的編程語言來解釋:

wKiom1WmVGnjDIhoAAAaPrHbUKw134.jpg

在面向對象的編程語言中,好比Son是一個實現類,Father是一個接口,Son要實現Father接口,必須使用implements顯式地聲明,同時在Son中實現Father裏面定義的方法,好比:

interface Father{

         getHour();

}


class Son implements Father{

         // 實現父接口Father定義的方法getHour()

         public int getHour(){

                 return 20;

         }      

}

一旦接口Father增長一個方法getSecond(),那麼實現該接口的全部孩兒都必須實現getSecond()方法。在使用時:

Father father = new Son();

即孩兒對象能夠賦值給Father接口


【備註】:若對上面面向對象編程語言不熟悉的話,建議看一下設計模式相關的書籍



(3)侵入式接口和非侵入式接口

像上面(2)中的Java就是侵入式接口。

GO語言中,像上面(1)所示,儘管定義了接口watch,但實現類iWatch並無顯示地聲明實現該接口,只是watch中的方法都已在iWatch中實現,那麼這種父子關係已創建,這種接口被稱爲「非侵入式接口」


七、引伸

上面例子中,爲iWatch定義了三個方法,如今咱們修改一下這三個方法:

// 爲*iWatch增長getHour()方法

func (w *iWatch) getHour() int {

        return time.Now().Hour()

}


// 爲*iWatch增長getMinute()方法

func (w *iWatch) getMinute() int {

        return time.Now().Minute()

}


// 爲*iWatch增長getSecond()方法

func (w *iWatch) getSecond() int {

        return time.Now().Second()

}

這至關於並非爲iWatch類型增長了三個方法,而是爲*iWatch類型增長了三個方法,那麼調用時也須要相應修改:

func main() {

        var w watch

        var t iWatch

        w = &t        

        fmt.Println("Current Hour:", w.getHour(), ", Minute:", w.getMinute(), ", Second:", w.getSecond())

}


好了,關於GO語言的接口類型就聊到這裏,請記住這麼三句話:

  • interface是類型

  • interface類型的變量能夠賦值

  • 任何實現了interface類型的具體類型變量,均可以賦值給interface類型的變量

相關文章
相關標籤/搜索