1 回答

TA貢獻(xiàn)2021條經(jīng)驗(yàn) 獲得超8個(gè)贊
我認(rèn)為通過動(dòng)態(tài)類型,您可能指的是在例如 C++ 和 Java 中,動(dòng)態(tài)綁定本質(zhì)上是對(duì)可以指向派生類的基類的引用(因?yàn)榕缮悺笆恰被悾?/p>
有人可能會(huì)說,基類定義了派生類變形的接口。如果派生類替換了基類的方法,對(duì)基類的引用仍然可以訪問派生類中的那些方法。
基類可以定義一些方法來為其派生類提供一些“基”功能。如果這些類沒有重新定義方法,則可以調(diào)用基類的方法。
在 go 中,這兩個(gè)概念都存在,但它們完全不同。
Go 有一個(gè)明確的interface關(guān)鍵字來定義方法簽名但沒有方法。如果任何值具有具有相同簽名的同名方法,則任何值都會(huì)隱式滿足該接口。
type LivingBeing interface {
TakeInEnergy()
ExpelWaste()
}
接口類型成為代碼中的有效類型。我們可以將接口傳遞給函數(shù),并且在不知道滿足該接口的類型的情況下,可以調(diào)用它的方法:
func DoLife(being LivingBeing) {
being.TakeInEnergy()
being.ExpelWaste()
}
這是有效的代碼,但不是完整的代碼。與其他語言的基類不同,接口不能定義函數(shù),只能定義它們的簽名。它純粹是一個(gè)接口定義。 我們必須將滿足接口的類型與接口本身分開定義。
type Organism struct{}
func (o *Organism) TakeInEnergy() {}
func (o *Organism) ExpelWaste() {}
我們現(xiàn)在有一個(gè)organism滿足LivingBeing. 它有點(diǎn)像基類,但如果我們想在它的基礎(chǔ)上構(gòu)建,我們不能使用子類化,因?yàn)?Go 沒有實(shí)現(xiàn)它。但是 Go 確實(shí)提供了類似的東西,稱為嵌入類型。
在這個(gè)例子中,我將定義一個(gè)新的有機(jī)體 Animal,它ExpelWaste()從 中提取LivingBeing,但定義了自己的TakeInEnergy():
type Animal struct {
Organism // the syntax for an embedded type: type but no field name
}
func (a *Animal) TakeInEnergy() {
fmt.Printf("I am an animal")
}
從該代碼中不明顯的是,因?yàn)锳nimal'sOrganism不是命名字段,所以它的字段和方法可以直接從Animal. 這幾乎就像Animal“是一個(gè)”有機(jī)體。
然而,它*不是*一個(gè)有機(jī)體。它是一種不同的類型,將對(duì)象嵌入視為語法糖以自動(dòng)將Organism的字段和方法提升為Animal.
由于 go 是靜態(tài)和顯式類型的,DoLife因此不能接受 anOrganism然后傳遞 an Animal:它沒有相同的類型:
/* This does not work. Animal embeds organism, but *is not* an organism */
func DoLife(being *Organism) {
being.TakeInEnergy()
being.ExpelWaste()
}
func main() {
var a = &Animal{Organism{}}
DoLife(&Animal{})
}
cannot use &Animal{} (type *Animal) as type *Organism in argument to DoLife
這就是interface存在的原因——因此Organismand Animal(實(shí)際上,甚至Plantor ChemotrophBacteria)都可以作為 LivingBeing.
綜上所述,這是我一直在使用的代碼:
package main
import "fmt"
type LivingBeing interface {
TakeInEnergy()
ExpelWaste()
}
type Organism struct{}
func (o *Organism) TakeInEnergy() {
}
func (o *Organism) ExpelWaste() {}
type Animal struct {
Organism
}
func DoLife(being LivingBeing) {
being.TakeInEnergy()
being.ExpelWaste()
}
func (a *Animal) TakeInEnergy() {
fmt.Printf("I am an animal")
}
func main() {
var a = &Animal{Organism{}}
DoLife(a)
}
有幾個(gè)注意事項(xiàng):
從語法上講,如果你想聲明一個(gè)嵌入的文字,你必須顯式地提供它的類型。在我的示例
Organism
中,沒有任何字段,因此無需聲明任何內(nèi)容,但我仍然將顯式類型留在那里以指向正確的方向。DoLife
可以調(diào)用TakeInEnergy
LivingBeing 的權(quán)利,但Organism
的方法不能。他們只看到嵌入的Organism
.
func (o *Organism) ExpelWaste() {
o.getWaste() //this will always be Organism's getWaste, never Animal's
}
func (o *Organism)getWaste() {}
func (a *Animal)getWaste() {
fmt.Println("Animal waste")
}
同樣,如果您只傳遞嵌入部分,那么它將調(diào)用它自己的TakeInEnergy(),而不是Animal; 沒有Animal了!
func main() {
var a = &Animal{Organism{}}
DoLife(&a.Organism)
}
總之,
定義顯式
interface
并在需要“多態(tài)”行為的任何地方使用該類型定義基本類型并將它們嵌入到其他類型中以共享基本功能。
不要期望“基本”類型會(huì)“綁定”到“派生”類型的函數(shù)。
- 1 回答
- 0 關(guān)注
- 93 瀏覽
添加回答
舉報(bào)