在go語言中,乙個介面型別總是代表著某一種型別(即所有實現它的型別)的行為。乙個介面型別的宣告通常會包含關鍵字type
、型別名稱、關鍵字inte***ce
以及由花括號包裹的若干方法宣告。示例如下:
type animal inte***ce注意,介面型別中的方法宣告是普通的方法宣告的簡化形式。它們只包括方法名稱、引數宣告列表和結果宣告列表。其中的引數的名稱和結果的名稱都可以被省略。不過,出於文件化的目的,我還是建議大家在這裡寫上它們。因此,
move
方法的宣告至少應該是這樣的:
move(new string) (old string)如果乙個資料型別所擁有的方法集合中包含了某乙個介面型別中的所有方法宣告的實現,那麼就可以說這個資料型別實現了那個介面型別。所謂實現乙個介面中的方法是指,具有與該方法相同的宣告並且新增了實現部分(由花括號包裹的若干條語句)。相同的方法宣告意味著完全一致的名稱、引數型別列表和結果型別列表。其中,引數型別列表即為引數宣告列表中除去引數名稱的部分。一致的引數型別列表意味著其長度以及順序的完全相同。對於結果型別列表也是如此。
例如,如果你正確地完成了上一小節的練習的話,*person
型別(注意,不是person
型別)就會擁有乙個move
方法。該方法會是animal
介面的move
方法的乙個實現。再加上我們在之前為它編寫的那個grow
方法,*person
型別就可以被看做是animal
介面的乙個實現型別了。
你可能已經意識到,我們無需在乙個資料型別中宣告它實現了哪個介面。只要滿足了「方法集合為其超集」的條件,就建立了「實現」關係。這是典型的無侵入式的介面實現方法。
好了,現在我們已經認為*person
型別實現了animal
介面。但是go語言編譯器是否也這樣認為呢?這顯然需要一種顯式的判定方法。在go語言中,這種判定可以用型別斷言來實現。不過,在這裡,我們是不能在乙個非介面型別的值上應用型別斷言來判定它是否屬於某乙個介面型別的。我們必須先把前者轉換成空介面型別的值。這又涉及到了go語言的型別轉換。
go語言的型別轉換規則定義了是否能夠以及怎樣可以把乙個型別的值轉換另乙個型別的值。另一方面,所謂空介面型別即是不包含任何方法宣告的介面型別,用inte***ce{}
表示,常簡稱為空介面。正因為空介面的定義,go語言中的包含預定義的任何資料型別都可以被看做是空介面的實現。我們可以直接使用型別轉換表示式把乙個*person
型別轉換成空介面型別的值,就像這樣:
p := person請注意第二行。在型別字面量後跟由圓括號包裹的值(或能夠代表它的變數、常量或表示式)就構成了乙個型別轉換表示式,意為將後者轉換為前者型別的值。在這裡,我們把表示式v := inte***ce{}(&p)
&p
的求值結果轉換成了乙個空介面型別的值,並由變數v
代表。注意,表示式&p
(&
是取址操作符)的求值結果是乙個*person
型別的值,即p
的指標。
在這之後,我們就可以在v
上應用型別斷言了,即:
h, ok := v.(animal)
Go 語言介面
go 語言提供了另外一種資料型別即介面,它把所有的具有共性的方法定義在一起,任何其他型別只要實現了這些方法就是實現了這個介面。例項 定義介面 type inte ce name inte ce 定義結構體 type struct name struct 實現介面方法 func struct name...
Go語言 介面
介面代表一種呼叫契約,是多個方法宣告的集合。介面要實現的是做什麼,而不關心如何做。介面最常見的使用場景是對包外提供訪問,或預留擴充套件空間。go語言介面實現機制很簡潔,只要目標型別方法集內包含介面宣告的全部方法,就被視為實現了該介面,無需做顯示宣告,當然目標型別可實現多個介面。其實介面也是一中結構,...
go語言介面
介面在底層的實現有兩個部分 type 和 data。在原始碼中,顯式地將 nil 賦值給介面時,介面的 type 和 data 都將為 nil。此時,介面與 nil 值判斷是相等的。但如果將乙個帶有型別的 nil 賦值給介面時,只有 data 為 nil,而 type 為 nil,此時,介面與 ni...