這是一個建立於
的文章,其中的資訊可能已經有所發展或是發生改變。
本文作者: 伯樂線上 - v7 。未經作者許可,禁止轉載!
歡迎加入伯樂線上 專欄作者。本篇通過具體樣本來展現 Golang 機制中 methods set 的繼承規則。
0x00 簡單method的規則
首先,我們聲明樣本的基本操作結構體。
Gotype Cat struct{ Name string Color string}
| 1234 |
type Cat struct{ Name string Color string} |
我們聲明了一個 Cat 的 type,在它的基礎上我們聲明一個Meow的method:
Gofunc (c Cat) Meow() { fmt.Println("Name:", c.Name, "Color:", c.Color)}
| 123 |
func (c Cat) Meow() { fmt.Println("Name:", c.Name, "Color:", c.Color)} |
在上面的代碼上, 我們聲明了一個method, 它的receiver是Cat(區別於Cat的指標),在這時,無論是我們通過 Cat類型的變數來調用method還是用 *Cat的類型來調用,Go都會正常的編譯並正常輸出,如:
,main函數中的 a 和 b 變數,一個是 Cat 類型,一個是Cat的指標類型,他們都有Meow方法。
那麼如果我們聲明的函數receiver是 *Cat呢?
func (c *Cat) Meow() { fmt.Println("Name:", c.Name, "Color:", c.Color)}
| 123 |
func (c *Cat) Meow() { fmt.Println("Name:", c.Name, "Color:", c.Color)} |
在這種情況下,方法也是繼承的:
上面是簡單的 Cat 和 *Cat 上的方法集的繼承規則:
普通情況下,類型 T 和 *T 上的方法集是互相繼承的。
0x01 介面中methods set的規則
接下來我們聲明一個介面來做對比:
type Meower interface{ Meow()}func Greet(meower Meower){ meower.Meow()}
| 12345678 |
type Meower interface{ Meow()} func Greet(meower Meower){ meower.Meow()} |
首先我們在Cat類型上實現Meower介面:
func (c Cat) Meow(){ fmt.Println("Name:", c.Name, " Color:", c.Color)}
| 123 |
func (c Cat) Meow(){ fmt.Println("Name:", c.Name, " Color:", c.Color)} |
此時編譯是沒問題的
也就是說,如果我們給Cat類型實現Meower的介面上Meow的方法,無論是Cat還是*Cat都是可以成為介面調用的。
那如果我們實現介面方式時候,選擇的receiver是*Cat呢?
func (c *Cat) Meow(){ fmt.Println("Name:", c.Name, " Color:", c.Color)}
| 123 |
func (c *Cat) Meow(){ fmt.Println("Name:", c.Name, " Color:", c.Color)} |
編譯不通過,如:
如果給指標實現Meow方法,在第26行出現了類型錯誤,提示我們Meow方法的receiver是一個指標類型,說明此時方法不能繼承。
於是這裡的規則是:
在介面中的method,對於普通類型T:
T的methods set裡不會繼承包含*T實現的method,除非T自己實現相對應的method。
但是,*T會繼承T的method set。
0x02 嵌入類型中methods set的規則
我們討論了上面兩種情況,那考慮如果Cat作為嵌入類型(Embedded Types)時會發生什麼呢?
於是在上面的基礎上,我們來聲明這樣一個類型來做實驗:
type BlackCat struct{ Cat Age int}
| 1234 |
type BlackCat struct{ Cat Age int} |
此時我們是直接可以通過BlackCat 來調用Cat實現的介面method的,
中,我們並沒有為BlackCat實現介面,僅僅為Cat實現了介面,不過BlackCat裡面嵌入了Cat的一個內部類型,也是可以通過介面調用函數Greet來調用到Meow method。
同時我們修改main函數,發現BlackCat的methods set 裡麵包含了Meow(), 如:
此時:
嵌入類型的類型中,外部類型自己未曾實現的methods被攜帶的內建函式實現時,外部類型也會將這些methods加入到自己的methods set裡。
那麼,如果外部類型BlackCat自己實現了Meow()函數(同時也實現了介面),內部和外部都實現的情況下會怎樣呢?
下面我們給BlackCat實現Meow()方法試一下:
func (c BlackCat) Meow(){ fmt.Println("BlackName:", c.Cat.Name, " Age:", c.Age)}
| 123 |
func (c BlackCat) Meow(){ fmt.Println("BlackName:", c.Cat.Name, " Age:", c.Age)} |
首先,編譯是沒問題的:
我們看一下a.Cat.Meow() 和 a.Meow()的運行結果:
發現BlackCat的使用了自己實現的方法,或者說它把內部Cat的Meow()方法覆蓋了。
將直接調用改成使用介面時也是如此:
兩次結果是一樣的。
0x03 結論
搞清Golang中的方法集繼承對我們寫出不囉嗦的代碼很有用處,而在Golang中,對於指標的處理也比C/C++中靈活了一些。
0x04 參考資料
Methods, Interfaces and Embedded Types in Go
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式
1 贊 1 收藏 評論
關於作者:v7
微博:@_v7__ 個人首頁 · 我的文章 · 17 ·