用复杂合理的模块扩展计算器(使用动态绑定)

Extend calculator with complex and rational module(using dynamic binding)

我已经制作了可以用整数和实数计算的计算器(我用 go 制作的)。 然后我想通过添加这些模块来计算复数和有理数。 (混合类型时也可以计算) 如果我每次(运行时)检查操作数的类型并处理每种情况,这可能很容易,但我想用动态绑定来解决它。伙计们,你能告诉我如何解决这个问题的想法

我认为通过动态类型,您可能指的是在例如 C++ 和 Java 中,动态绑定本质上是引用一个可以指向派生 [=] 的基 class 128=](因为派生的class“是一个”基础class)。

有人可能会说基础 class 定义了 接口 ,其后派生了 classes 变形。如果派生 classes 替换基 class 的方法,对基 class 的引用仍然可以访问派生 class.

中的那些方法

Base class 可以定义一些方法来为其派生的 classes 提供一些“基本”功能。如果那些class不重定义方法,可以调用基础class的方法。

在围棋中,这两个概念都存在,但它们有很大的不同。

Go 有一个明确的 interface 关键字,它定义了方法签名但没有方法。任何值 隐含地 满足该接口,如果它具有具有相同签名的相同名称的方法。

type LivingBeing interface {
    TakeInEnergy()
    ExpelWaste()
}

接口类型成为代码中的有效类型。我们可以将一个接口传递给一个函数,并且在不知道满足该接口的类型的情况下,可以调用它的方法:

func DoLife(being LivingBeing) {
   being.TakeInEnergy()
   being.ExpelWaste()
}

这是有效代码,但不是完整代码。与其他语言中的基础 classes 不同,接口不能定义函数,只能定义它们的签名。它纯粹且只是一个接口定义。 我们必须将满足接口的类型与接口本身分开定义

type Organism struct{}

func (o *Organism) TakeInEnergy() {}

func (o *Organism) ExpelWaste() {}

我们现在有一个满足 LivingBeing 的类型 organism。它有点像一个 base class,但是如果我们想在它上面构建,我们不能使用 subclassing 因为 Go 没有实现它。但是 Go 确实提供了类似的东西,叫做 embedding types.

在这个例子中,我将定义一个新的生物体 Animal,它从 LivingBeing 中提取 ExpelWaste(),但定义了它自己的 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")
}

从该代码中不明显的是,因为 AnimalOrganism 不是命名字段,所以它的字段和方法可以直接从 Animal 访问。 几乎就好像Animal是一个n”有机体。

然而它*不是*一个有机体。它是一种不同的类型,将对象嵌入视为自动将 Organism 的字段和方法提升为 Animal.

的语法糖会更准确

由于 go 是静态和显式类型的,DoLife 不能采用 Organism 然后传递给 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 存在的原因 - 这样 OrganismAnimal(实际上,甚至 PlantChemotrophBacteria)都可以通过 作为LivingBeing.

将所有内容放在一起,这里是 the code I've been working from:

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)
}

有几点注意事项:

  1. 语法上,如果你想声明一个嵌入文字,你必须显式地提供它的类型。在我的示例中,Organism 没有字段,因此没有什么可声明的,但我仍然在其中保留了显式类型,以便为您指明正确的方向。

  2. DoLife可以调用LivingBeing的右边TakeInEnergy,但是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 并在任何需要“多态”行为的地方使用该类型

  • 定义基本类型并将它们嵌入其他类型以共享基本功能。

  • 不要指望“基本”类型会“绑定”到“派生”类型的函数。