什麼是接口?
在 Go 中,接口是一種類型,它定義了一組方法簽名(即方法名、參數和返回值),但不包含這些方法的具體實現。
換句話説,接口描述了“一個類型能做什麼”,而不是“它是什麼”。
接口的定義
使用 interface 關鍵字定義接口:
type Speaker interface {
Speak() string
}
這個 Speaker 接口規定:任何實現了 Speak() string 方法的類型,都自動滿足(implement)該接口。
隱式實現:Go 的優雅之處
與其他語言(如 Java、C#)不同,Go 中不需要顯式聲明某個類型實現了某個接口。只要你的類型擁有接口中定義的所有方法,它就“自動”實現了該接口。
來看一個例子:
package main
import "fmt"
// 定義接口
type Speaker interface {
Speak() string
}
// 定義兩個結構體
type Dog struct {
Name string
}
type Cat struct {
Name string
}
// 為 Dog 實現 Speak 方法
func (d Dog) Speak() string {
return d.Name + " says: Woof!"
}
// 為 Cat 實現 Speak 方法
func (c Cat) Speak() string {
return c.Name + " says: Meow!"
}
func main() {
var s Speaker
s = Dog{Name: "Buddy"}
fmt.Println(s.Speak()) // Buddy says: Woof!
s = Cat{Name: "Mimi"}
fmt.Println(s.Speak()) // Mimi says: Meow!
}
在這個例子中:
Dog和Cat並沒有聲明“我實現了 Speaker 接口”;- 但因為它們都有
Speak() string方法,所以它們自動滿足Speaker接口; - 因此可以賦值給
Speaker類型的變量。
這種“鴨子類型”(Duck Typing)的設計,讓 Go 的代碼更加靈活、解耦。
空接口:interface{}
Go 中有一個特殊的接口叫 空接口:
interface{}
它不包含任何方法,因此所有類型都實現了空接口。這使得 interface{} 可以接收任意類型的值,類似於其他語言中的 “any” 或 “Object”。
func PrintAnything(v interface{}) {
fmt.Println(v)
}
PrintAnything(42) // int
PrintAnything("hello") // string
PrintAnything([]int{1,2,3}) // slice
⚠️ 注意:雖然空接口很靈活,但過度使用會削弱類型安全。在 Go 1.18 引入泛型後,很多原本用
interface{}的場景現在可以用泛型替代。
接口的用途
- 多態性:同一接口變量可指向不同類型的實例,調用各自的方法。
- 解耦:函數依賴接口而非具體類型,便於測試和擴展。
- 標準庫廣泛使用:如
io.Reader、io.Writer、error等都是接口。
例如,error 接口定義如下:
type error interface {
Error() string
}
只要你自定義的類型實現了 Error() string,就可以作為錯誤返回!