【高級數據類型2】- 10. 接口

Go語言-接口

    在Go語言中,一個接口類型老是表明着某一種類型(即全部實現它的類型)的行爲。一個接口類型的聲明一般會包含關鍵字type、類型名稱、關鍵字interface以及由花括號包裹的若干方法聲明。示例以下:編程

type Animal interface {
    Grow()
    Move(string) string
}

    注意,接口類型中的方法聲明是普通的方法聲明的簡化形式。它們只包括方法名稱、參數聲明列表和結果聲明列表。其中的參數的名稱和結果的名稱均可以被省略。不過,出於文檔化的目的,我仍是建議你們在這裏寫上它們。所以,Move方法的聲明至少應該是這樣的:併發

Move(new string) (old string)

    若是一個數據類型所擁有的方法集合中包含了某一個接口類型中的全部方法聲明的實現,那麼就能夠說這個數據類型實現了那個接口類型。所謂實現一個接口中的方法是指,具備與該方法相同的聲明而且添加了實現部分(由花括號包裹的若干條語句)。相同的方法聲明意味着徹底一致的名稱、參數類型列表和結果類型列表。其中,參數類型列表即爲參數聲明列表中除去參數名稱的部分。一致的參數類型列表意味着其長度以及順序的徹底相同。對於結果類型列表也是如此。
  
    例如,若是你正確地完成了上一小節的練習的話,*Person類型(注意,不是Person類型)就會擁有一個Move方法。該方法會是Animal接口的Move方法的一個實現。再加上咱們在以前爲它編寫的那個Grow方法,*Person類型就能夠被看作是Animal接口的一個實現類型了。
  
    你可能已經意識到,咱們無需在一個數據類型中聲明它實現了哪一個接口。只要知足了「方法集合爲其超集」的條件,就創建了「實現」關係。這是典型的無侵入式的接口實現方法。
  
    好了,如今咱們已經認爲*Person類型實現了Animal接口。可是Go語言編譯器是否也這樣認爲呢?這顯然須要一種顯式的斷定方法。在Go語言中,這種斷定能夠用類型斷言來實現。不過,在這裏,咱們是不能在一個非接口類型的值上應用類型斷言來斷定它是否屬於某一個接口類型的。咱們必須先把前者轉換成空接口類型的值。這又涉及到了Go語言的類型轉換。
  
    Go語言的類型轉換規則定義了是否可以以及怎樣能夠把一個類型的值轉換另外一個類型的值。另外一方面,所謂空接口類型便是不包含任何方法聲明的接口類型,用interface{}表示,常簡稱爲空接口。正由於空接口的定義,Go語言中的包含預約義的任何數據類型均可以被看作是空接口的實現。咱們能夠直接使用類型轉換表達式把一個*Person類型轉換成空接口類型的值,就像這樣:spa

p := Person{"Robert", "Male", 33, "Beijing"}
v := interface{}(&p)

    請注意第二行。在類型字面量後跟由圓括號包裹的值(或可以表明它的變量、常量或表達式)就構成了一個類型轉換表達式,意爲將後者轉換爲前者類型的值。在這裏,咱們把表達式&p的求值結果轉換成了一個空接口類型的值,並由變量v表明。注意,表達式&p&是取址操做符)的求值結果是一個*Person類型的值,即p的指針。
  
    在這以後,咱們就能夠在v上應用類型斷言了,即:指針

h, ok := v.(Animal)

    類型斷言表達式v.(Animal)的求值結果能夠有兩個。第一個結果是被轉換後的那個目標類型(這裏是Animal)的值,而第二個結果則是轉換操做成功與否的標誌。顯然,ok表明了一個bool類型的值。它也是這裏斷定實現關係的重要依據。
  
    至此,咱們掌握了接口類型、實現類型以及實現關係斷定的重要知識和技巧。關於Go語言的類型轉換規則的更多細節請參看Go語言規範或《Go併發編程實戰》中的相關內容。而至於爲何只有*Person類型才實現了Animal接口,請參看後面兩節。code

相關文章
相關標籤/搜索