embedded,嵌入。
俗稱golang 的繼承,但不是真的繼承(背後的機制和程式語言處理方式不同)。
而行為可以做到類似繼承的特點。
子類別A繼承了父類別B,子類別A可以寫跟父類別同樣名字的method name,同樣的input 和output,method內部的細節卻不同,達到覆寫父類別method的目的。
golang也可以做出這樣的特點。
type Cellphone struct {
ID int
name string
}
type Iphone struct {
Cellphone
}
type HTC struct {
Cellphone
}
func main() {
newIphone := Iphone{}
fmt.Println(newIphone)
// 不可這樣使用
newIphone2 := Iphone{
ID: 1,
}
fmt.Println(newIphone2)
}
會有錯誤訊息如下
cannot use promoted field Cellphone.ID in struct literal of type Iphone
意思是說Iphone是嵌入Cellphone的型態。
嵌入的對象,裡面的變數有個專有名詞,叫做『promoted field』,初始化struct不可以這樣用。
稍微改造一下
newIphone2 := Iphone{
Cellphone{
ID: 1,
name: "iphone",
},
}
fmt.Printf("%#v", newIphone2)
印出內容
main.Iphone{Cellphone:main.Cellphone{ID:1, name:"iphone"}}
我們新增一個屬於Cellphone的method
func (c *Cellphone) SetID(n int) {
c.ID = n + 100
}
func main() {
newIphone2 := Iphone{
Cellphone{
ID: 1,
name: "iphone",
},
}
newIphone2.SetID(99)
fmt.Printf("%#v", newIphone2)
}
結果會是
main.Iphone{Cellphone:main.Cellphone{ID:199, name:"iphone"}}
因為iphone沒有SetID的method,所以使用Cellphone的SetID
那麼,我再也加一個屬於iphone的SetID()
func (i *Iphone) SetID(n int) {
i.ID = n + 500
}
再次執行結果會是
main.Iphone{Cellphone:main.Cellphone{ID:599, name:"iphone"}}
結論是如果自己沒有指定的method,就使用嵌入型態的method。
若有自己的method,就使用自己的,而不使用嵌入型態的method,這個行為很像我們物件導向使用的繼承吧。
改造Iphone的SetID()
func (c *Cellphone) SetID(n int) {
c.ID = n + 100
}
func (i *Iphone) SetID(n int) {
i.ID = n + 500
i.Cellphone.SetID(-1000)
}
結果會是如下
main.Iphone{Cellphone:main.Cellphone{ID:-900, name:"iphone"}}
Embedded 使用方式在golang也是常見的設計方式之一,io package那包source code就非常的經典。
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
Reader
Writer
}
不只是struct,interface也是可以用embedded。
(前幾篇的系列文大概也讓你意識到了,會出現在這裡的interface,都可以看作背後站個struct,只是我們只知道有什麼method,不知道有struct實際有什麼其他的變數,或者interface沒列出的method)。
大抽象可以是小抽象組合而成的,一來是程式碼方便重複使用,只需要客製不同的部分,二來是方便管理,拆成小元件比起許多很類似的新個體,維護性更佳。
看懂embedded,對於golang程式閱讀和設計又可以更近一步了。