用复杂合理的模块扩展计算器(使用动态绑定)
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")
}
从该代码中不明显的是,因为 Animal
的 Organism
不是命名字段,所以它的字段和方法可以直接从 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
存在的原因 - 这样 Organism
和 Animal
(实际上,甚至 Plant
或 ChemotrophBacteria
)都可以通过 作为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)
}
有几点注意事项:
语法上,如果你想声明一个嵌入文字,你必须显式地提供它的类型。在我的示例中,Organism
没有字段,因此没有什么可声明的,但我仍然在其中保留了显式类型,以便为您指明正确的方向。
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
并在任何需要“多态”行为的地方使用该类型
定义基本类型并将它们嵌入其他类型以共享基本功能。
不要指望“基本”类型会“绑定”到“派生”类型的函数。
我已经制作了可以用整数和实数计算的计算器(我用 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")
}
从该代码中不明显的是,因为 Animal
的 Organism
不是命名字段,所以它的字段和方法可以直接从 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
存在的原因 - 这样 Organism
和 Animal
(实际上,甚至 Plant
或 ChemotrophBacteria
)都可以通过 作为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)
}
有几点注意事项:
语法上,如果你想声明一个嵌入文字,你必须显式地提供它的类型。在我的示例中,
Organism
没有字段,因此没有什么可声明的,但我仍然在其中保留了显式类型,以便为您指明正确的方向。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
并在任何需要“多态”行为的地方使用该类型定义基本类型并将它们嵌入其他类型以共享基本功能。
不要指望“基本”类型会“绑定”到“派生”类型的函数。