Go 語言基礎系列(八):面向對象編程之接口
什麼是接口
上一篇我們說過:Golang 語言是通過結構體和接口來實現面向對象編程的思想。
並且對結構體進行了比較詳細的介紹,本篇我們開始學習接口。那麼不禁要問:什麼是接口?
接口是一組還未具體實現的方法的集合。
面向對象編程的三個特點:封裝,繼承和多態。上一篇我們學習了結構體,我們提到了封裝和繼承的概念。對於接口,主要體現的是面向對象編程的——**多態,**那麼多態是什麼呢?多態是一個對象具有多重特徵,在不同的狀態下,體現出不同的特徵和方法
思維邏輯圖如下:
下面我們從以上四個方面對 **接口 **進行相應的介紹
** 接口創建 **
創建一個接口是相對簡單的,接口創建是通過關鍵字 type 和關鍵字 interface 組合實現的,格式如下:
type 接口名字 interface {
** 方法 1 名字 (入參)返回值類型
**
** 方法 2 名字 (入參)返回值類型**
** ...
**
}
**示例:**創建了一個 Annimal 的接口,並且包含了兩個方法,分別是 Name 和 Eat。
解釋:在 Annimal 接口中我們之所以定義了 Name 和 Eat 方法,是因爲首先動物都有名字,不管是兔子還是老虎,其次動物都喫食物,無論是喫胡蘿蔔還是肉;所以我們只定義了方法,而無需具體實現
** 接口實現 **
接口實現是指:
對於某一類型實現了接口定義的所有方法,則該類型便實現了此接口,並且是此接口的實例。不同於 Java 的顯示實現(implements 關鍵字),Golang 是 “隱式” 實現
注:1. 一個類型可以實現多個接口; 2. 一個接口可以被多個類型實現;3. 任何類型都實現了空接口(空接口我們後面介紹)
我們來實現上面的 Annimal 接口
解釋:如上,我們定義了 Rabbit 這一結構體類型,它實現了 Annimal 中的兩個方法,所以其是 Annimal 接口的實現,是 Annimal 接口的實例。左側的小綠圈是 GolandIDE 對於接口實現的提示
同樣的,老虎也實現接口
完整代碼如下:
上面,Rabbit 和 Tiger 都實現了 Annimal 接口,那麼多態的體現在哪裏呢?其實,此時並沒有表現出多態,大家可以看到在 main 函數中,對於 rabbit 和 tiger 兩個實例都得分別調用 Name 和 Eat 方法,是不是也比較繁瑣呢?那麼可不可以有一個統一的處理呢?有!如下:
相對於之前的代碼,我們這裏新定義了一個函數:getAnnimal,main 函數也做了相應的調整,大家會發現,對於 getAnnimal 函數可以處理不同類型的數據,anni 入參表現出了多重的特徵,可以是 Rabbit,也可以是 Tiger,這便是 Golang 的多態體現
當然,上面兩種方式結果都一樣:
** 接口使用 **
前面我們創建並實現了接口,那麼自然而然地該使用它了。接口的使用主要爲接口的賦值和接口的組合,而接口的賦值又可分爲對象與接口的賦值,以及接口與接口之間的賦值
**
01
** 對象與接口賦值**
**
對象與接口賦值是指實現了該接口的類型對象賦值給該接口變量,由於我們在上篇提到結構體分爲值類型接收者和指針類型接收者,所以這裏涉及兩種情況:
**1)指針類型接收者對象與接口賦值
**
解釋:由於是指針類型接收者,所以在 main 函數中賦值時,我們須將指針類型對象賦值給接口
2)值類型接收者對象與接口賦值
解釋:由於是值類型接收者,所以在 main 函數中賦值時,我們可以將值類型對象賦值給接口,也可以將指針類型對象賦值給對象(上一篇有提到)
**02
**
**** 接口與接口賦值****
接口與接口的賦值通常發生在兩個方法定義不相同的接口之間,而且這兩個接口的方法是包含與被包含的關係。假如有兩個接口:A 與 B。A 接口的方法是 B 接口方法的子集,那麼 B 接口的對象可以賦值給 A 接口。這種實現主要是我們對一些變量的功能進行一定程度的約束
示例如下:我們再創建一個肉食動物的接口,只包含一個 Eat 方法
解釋:將 Annimal 接口的變量賦值給 CarnivorousAnnimal 接口變量,使得 Annimal 接口變量的擁有的方法減少,僅有 Eat 方法
**03
**
**** 接口組合****
接口組合有點像上篇中提到的結構體內嵌。接口組合是一種繼承的表現形式。如果接口 A 被包含於接口 B 中,那麼接口 B 則擁有了接口 A 的所有方法。這種實現主要是對一些變量的功能進擴展
示例如下:我們創建了一個新 People 的接口,我們知道人是可以工作的高等動物,但是人也是有名字並且需要進食的,所以讓其包含 Annimal 接口,這便擁有了 Annimal 接口的所有方法
解釋:創建了兩個接口分別爲:Annimal 和 People,People 組合了 Annimal 接口,所以當 XiaoMing 結構體實現了 People 接口,同時便實現了 Annimal 接口
** 空接口 **
空接口是指不包含任何方法的接口,所以可以認爲任何類型都實現了空接口。所以可以將任何類型的值賦值給空接口,相當於空接口可以存儲任意類型的值;反過來,有時候我們想知道這個空接口存的值的類型是什麼,那怎麼操作呢?這便是類型斷言,當然類型斷言還可以判斷接口變量是否實現了某接口;所以本小節我們介紹空接口存值和類型斷言
**01
**
**** 空接口存值****
因爲空接口存值比較簡單,我們這裏通過例子讓大家直觀的感受一下即可
示例:我們將不同的類型均賦值給空接口
結果如下:
以上我們對常見的類型進行了賦值,除此之外,自定義的類型也可以賦值給空接口。大家可以自己實踐一下
**02
**
**** 類型斷言****
前面我們提到,類型斷言是我們反過來想看看接口變量存的值的類型是什麼類型,或者看看該接口變量有沒有實現某個接口。格式如下:
t, ok := X.(T)
**注:**1. 斷言成功,t 爲 X 的值,ok 爲 true;
2. 斷言失敗,t 爲 T 的默認初始值,ok 爲 false;
3. T 便是我們提到的可以是具體某種類型,也可以是某個接口;
所以這裏我們分兩種方式進行介紹
1)T 爲某種具體類型
示例如下:
結果如下:
解釋:我們對 v1 和 v2 分別做了斷言,v1 斷言成功,所以 t1 爲 v1 的值;v2 斷言失敗,t2 爲類型 int 的默認初始值 0;v3 的斷言是我們的自定義類型,同樣斷言成功
**2)T 爲某個接口 :**我們通過類型類型斷言,判斷某個結構體變量是否實現某個接口
這裏我們仍然用前文用過的 Annimal 和 People 接口的那個例子,只是對 XiaoMing 結構體做了一個小小的改動,讓其有一個 Age 的字段,這樣方便我們斷言後觀察
示例如下:
結果如下:
可見,通過類型斷言可以幫助我們判斷變量是否實現 People 接口,而且斷言成功後的值爲該變量的值,大家也可以測試一下該變量是否實現了 Annimal 接口,結果是一樣的
到此關於 Golang 面向對象編程之接口的分享就結束了~
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/cJf660raLfQ4HmSijkD7RA