第 12 天要來介紹 interface
那麼話不多說,我們就進入正題吧 ─=≡Σ(((っ゚∀゚)っ
再開始討論 interface 前,先讓我們回憶一下 struct 及 methods,這兩個型態是 Go 用來實踐物件導向很重要的行為。
// 定義 & 屬性
type User struct {
Id int
Name string
Age int
}
// 定義 & 行為
func (u User) greeting() string {
return "hi, " + u.Name
}
而 interface 就是透過將不同 type 的相同行為給集合起來,在執行 interface 時不用再為各個 type 指定使用方法。
使用的方式,就讓我們派出人人都愛的貓貓狗狗吧!
type Dog struct {
Name string
}
type Cat struct {
Name string
}
// 讓貓貓狗狗吃吃喝喝!
func (d *Dog) eat() {
fmt.Println(d.Name, "吃肥宅餐")
}
func (d *Dog) drink() {
fmt.Println(d.Name, "喝肥宅水")
}
func (c *Cat) eat() {
fmt.Println(c.Name, "吃快樂餐")
}
func (c *Cat) drink() {
fmt.Println(c.Name, "喝快樂水")
}
他們都會有共同的方法可以使用,這時候就能夠把他們的共同行為透過 interface 定義起來:
貓跟狗都會吃吃喝喝 => 動物都會吃吃喝喝
既然抓到這個概念,這樣我們的 interface 就能夠用 Animal 來定義:
type Animal interface {
eat()
drink()
}
並且定義一個方法,讓 Cat 跟 Dog 生出的實體,透過參數傳進去:
func goEat(a Animal) {
a.eat()
}
func goDrink(a Animal) {
a.drink()
}
因為是 Animal interface,因此我們傳入的參數也需要是 Animal 型態,而這些被傳入的其他型別,就會把自己歸類為 Animal。
為什麼會有這樣的行為,就需要特別介紹 Duck typing 是什麼:
不是由繼承自特定的類別或實現特定的介面,而是由當前方法和屬性的集合決定。因此「當看到一隻鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就可以被稱為鴨子。」
(圖片來自影集 Lucifer)
回到剛才的例子,只要能夠被丟進 Animal 類別的,就會被當作 Animal 來使用。
實際的應用就會是這樣:
package main
import "fmt"
type Animal interface {
eat()
drink()
}
type Dog struct {
Name string
}
type Cat struct {
Name string
}
func (d *Dog) eat() {
fmt.Println(d.Name, "吃肥宅餐")
}
func (d *Dog) drink() {
fmt.Println(d.Name, "喝肥宅水")
}
func (c *Cat) eat() {
fmt.Println(c.Name, "吃快樂餐")
}
func (c *Cat) drink() {
fmt.Println(c.Name, "喝快樂水")
}
func goEat(a Animal) {
a.eat()
}
func goDrink(a Animal) {
a.drink()
}
func main() {
dog := Dog{Name: "MeiMei"}
cat := Cat{Name: "BuiBui"}
goEat(&dog)
goDrink(&cat)
}
// => MeiMei 吃肥宅餐
// BuiBui 喝快樂水
登愣,雖然我一開始待補,但內容從不缺席。
interface 的內容也到此結束,有任何問題歡迎與我告知 :)
此篇文章同步更新於 我的部落格