這個文章源自下面的問題
不過想問問專業的⋯⋯Golang 都有 interface 這種東西,提供泛型的必要性是什麼啊?
這是個常見的誤解,因為大部分語言不會多認真跟你講清楚到底啥是啥,看來好像都能接受多種不同的類型輸入不是嗎?所以這裡我們就來看各種機制的定義跟差別。
Go 的 interface [tt-000M]
Go 的 interface [tt-000M]
Go 語言的 interface,範例如下
type Abser interface { Abs() float64 }
其中的 Abs() float64
可以被改寫成抽象語法 Abs : () -> float64
。因此一個 interface
有一組與其關聯的一系列簽名
。並且,對 Go 而言下列的兩個 interface 並沒有差異
type A interface { F(C) D } type B interface { F(C) D }
因此我們可以更進一步認為 Go 的一個 interface 可以完全由其簽名 替換。
Java 的 interface 與 bounded polymorphism (bounded quantification) [tt-000N]
Java 的 interface 與 bounded polymorphism (bounded quantification) [tt-000N]
在 Java 之中可以定義 interface,範例如下
interface Comparable{ int compareTo(T other); }
相較於 [Go 中不用明確宣告](tt-000D),在 Java 中實現 interface I
需要寫成 class T extends I
,因此雖然 Java 的 interface
也有其相關的一組簽名
,但兩個有同樣簽名
的 interface 不是同一個型別。
而在 Java 中 bounded polymorphism 指的是以下的 interface 使用方法:
<S extends Comparable> S min(S a, S b)
這會使得沒有明確宣告實現 Comparable
的型別無法被傳為 min
的引數。
問題所在 [tt-000O]
問題所在 [tt-000O]
現在考慮一個簽名
在 Java 裡面可以確實保證兩個參數跟回傳的型別都是同一個。在 Go 裡面這個簽名就只能寫成
而兩個參數跟回傳的型別不一定相同。現在我們就會發現乍看之下 interface 對類型的約束跟多型一樣可以被多個不同的型別滿足,但事實上根本就是不同的東西。
interface 是一種子類型關係,換句話說當 實現 我們就說 ,在每個要求 的位置都可以用 取代。
多型的本體是一個型別等級的參數!在語意學上,上面的簽名可以改寫成 ,當你寫下
的時候,乍看之下是一個完整的呼叫。實際上編譯器會先推導 的類型,記作 ,譬如假設 則 ,這時候就可以做型別替換 得出 。因此真正的呼叫程式碼是
子類型規則並不能取代替換這個語意。在 Java 的 規則下,僅是多檢查了 是否為真,子類型與多型仍然是不同的規則。