我已經制作了可以用整數和實數計算的計算器(我用 go 做的)。然后我想通過添加這些模塊來計算復數和有理數。(它也可以計算混合型別)如果我每次(運行時)檢查運算元的型別并處理每種情況,這很容易,但我想用動態系結來解決它。伙計們,你能告訴我如何解決這個問題的想法嗎
uj5u.com熱心網友回復:
我認為通過動態型別,您可能指的是在例如 C 和 Java 中,動態系結本質上是如何參考可以指向派生類的基類(因為派生類“是”基類)。
有人可能會說基類定義了派生類變形背后的介面。如果派生類替換了基類的方法,對基類的參考仍然可以訪問派生類中的那些方法。
基類可以定義一些方法來為其派生類提供一些“基本”功能。如果這些類不重新定義方法,則可以呼叫基類的方法。
在 Go 中,這兩個概念都存在,但它們完全不同。
Go 有一個明確的interface關鍵字來定義方法簽名但沒有定義方法。如果任何值具有具有相同簽名的同名方法,則它隱式地滿足該介面。
type LivingBeing interface {
TakeInEnergy()
ExpelWaste()
}
介面型別成為代碼中的有效型別。我們可以將介面傳遞給函式,并且在不知道滿足該介面的型別的情況下,可以呼叫其方法:
func DoLife(being LivingBeing) {
being.TakeInEnergy()
being.ExpelWaste()
}
這是有效的代碼,但不是完整的代碼。與其他語言中的基類不同,介面不能定義函式,只能定義它們的簽名。它純粹是一個介面定義。 我們必須獨立于介面本身定義滿足介面的型別。
type Organism struct{}
func (o *Organism) TakeInEnergy() {}
func (o *Organism) ExpelWaste() {}
我們現在有一個organism滿足LivingBeing. 它有點像基類,但是如果我們想在它上面構建,我們不能使用子類,因為 Go 沒有實作它。但是 Go 確實提供了類似的東西,稱為嵌入型別。
在這個例子中,我將定義一個新的有機體 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")
}
從該代碼中不明顯的是,因為Animal'sOrganism不是命名欄位,它的欄位和方法可以直接從Animal. 這幾乎就像Animal“是一個”有機體。
然而,它*不是*一個有機體。它是一種不同的型別,將物件嵌入視為自動將Organism的欄位和方法提升到 的語法糖會更準確Animal。
由于 go 是靜態和顯式型別的,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存在的原因- 這樣Organism和Animal(實際上,甚至Plant或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)
}
有幾個注意事項:
從語法上講,如果要宣告嵌入文字,則必須明確提供其型別。在我的例子
Organism中沒有欄位,所以沒有什么要宣告的,但我仍然在那里留下了顯式型別,以便為您指明正確的方向。DoLife可以TakeInEnergy在 LivingBeing 上呼叫 right ,但是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")
}
同樣,如果您只傳遞嵌入的部分,那么它將呼叫自己的TakeInEnergy(),而不是Animal; 沒有Animal剩下了!
func main() {
var a = &Animal{Organism{}}
DoLife(&a.Organism)
}
總之,
定義顯式
interface并在您想要“多型”行為的任何地方使用該型別定義基本型別并將它們嵌入其他型別以共享基本功能。
不要期望“基本”型別永遠“系結”到“派生”型別的函式。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/369639.html
上一篇:在C 中抽象容器
