为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

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

1 回答

?
宝慕林4294392

TA贡献2021条经验 获得超8个赞

我认为通过动态类型,您可能指的是在例如 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存在的原因——因此Organismand Animal(实际上,甚至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)

}


有几个注意事项:

  1. 从语法上讲,如果你想声明一个嵌入的文字,你必须显式地提供它的类型。在我的示例Organism中,没有任何字段,因此无需声明任何内容,但我仍然将显式类型留在那里以指向正确的方向。

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

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

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


查看完整回答
反对 回复 2022-10-17
  • 1 回答
  • 0 关注
  • 114 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号