最簡單的形式下,介面型別是一組方法簽章。
以下是介面定義的範例,其中包含 Add 和 Value 兩個方法:
type Counter interface {
Add(increment int)
Value() int
}
介面定義中的參數名稱(例如 increment)可以省略,但保留它們通常能提升可讀性。
Go 的介面名稱不含 Interface 或 I 這個字。
它們通常以 er 結尾,例如 Reader、Stringer。
任何定義了介面方法的型別,都會自動隱含地「實作」該介面。
Go 裡沒有 implements 關鍵字。
以下型別實作了上面看到的 Counter 介面。
type Stats struct {
value int
// ...
}
func (s Stats) Add(v int) {
s.value += v
}
func (s Stats) Value() int {
return s.value
}
func (s Stats) SomeOtherMethod() {
// The type can have additional methods not mentioned in the interface.
}
對實作介面來說,方法用的是值接收器還是指標接收器都無所謂。 (如果你對這些概念不太確定,可以複習方法的概念。)
介面型別的值可以存放任何實作了這些方法的值。[^1]
這表示 Stats 現在可以用在所有需要 Counter 介面的地方。
func SetUpAnalytics(counter Counter) {
// ...
}
stats := Stats{}
SetUpAnalytics(stats)
// works because Stats implements Counter
因為介面是隱含實作的,一個型別可以輕鬆實作多個介面。 它只需要定義所有必要的方法就好。
Go 有一個非常特別的介面型別:空介面,它不包含任何方法。
空介面寫成這樣:interface{}。
any 是 interface{} 的別名,而且更常被使用。
由於空介面沒有任何方法,每個型別都會隱含地實作它。 這在定義能泛型地接受任何值的函式時很有幫助。 這種情況下,函式的參數會使用空介面型別。
柏林的新機場為了他們的機器人實驗室招募了開發者,而你即將在那裡開始上班。 他們有一些笨重、外型有點像人形的機器人,他們正試著用這些機器人來改善客戶服務。
你上班後的第一項任務,就是寫一支程式,讓機器人在旅客於自助報到櫃檯掃描護照之後,能用旅客的母語問候他們。
這台機器人對自己的能力很自豪,所以它總是會先說自己會說哪種語言,然後再問候對方。 舉例來說,如果有人掃描的是德國護照,機器人就會說:
I can speak German: Hallo Dietrich!
你不需要自己撰寫各種語言的程式碼,所以你得先把機器人的程式碼結構設計好,讓其他開發者之後能輕鬆加入更多語言。
第一步,定義一個介面 Greeter,裡面有兩個方法。
LanguageName:回傳機器人應該用來問候訪客的語言名稱(string)。Greet:接受訪客的名字(string),並回傳帶有特定語言問候訊息的string。接著,實作一個函式 SayHello,它接受訪客的名字,以及任何實作了 Greeter 介面的東西作為引數,並回傳想要的問候字串。
舉例來說,想像一個德文的 Greeter 實作,它的 LanguageName 會回傳 "German",而 Greet 會回傳 "Hallo {name}!":
SayHello("Dietrich", germanGreeter)
// => "I can speak German: Hallo Dietrich!"
現在,你的任務是讓機器人也能為掃描義大利護照的人服務。
為此,建立一個 struct Italian,並實作兩個方法,讓這個 struct 能滿足你在任務 1 建立的 Greeter 介面。
用義大利文問候別人時,可以說 "Ciao {name}!"。
在你收工之前,還得完成用葡萄牙文問候別人的功能。
為此,建立一個 struct Portuguese,並同樣實作讓這個 struct 能滿足 Greeter 介面所需的兩個方法。
用葡萄牙文問候別人時,可以說 "Olá {name}!"。