我要从Java开始,有些事情让我困惑。
例如,让我们考虑以下代码:
package main
import (
"fmt"
)
type I interface {
Do()
MegaDo()
}
type A struct {
}
func (a *A) Do() {
fmt.Println("A")
}
func (a *A) MegaDo() {
a.Do()
}
type B struct {
A
}
func (a *B) Do() {
fmt.Println("B")
}
var i I
func main() {
fmt.Println("Hello, playground")
var i I = &B{}
i.MegaDo()
}
此处我们有一个界面I
,其中包含方法Do()
和MegaDo()
。 Struct A
在内部实现两种方法和MegaDo
调用Do
。 B
由A
组成,仅覆盖Do()
如果我在Java中模仿相同的代码,我希望它可以打印" B"。但在Go中,它打印了#34; A"。
虽然我有点理解它为什么会发生(因为它嵌入而不是继承)我想知道如何在Go中模仿同样的东西。 例如,我有两个相同接口的实现,只有一点点不同。在这种情况下,如何最大化代码重用?我无法相信,为了在一个实现中自定义位逻辑,我必须复制粘贴所有内容并只修复我的代码中的一小部分。 也许在Go中有一些惯用的方法吗?
答案 0 :(得分:6)
你的问题太抽象了,无法回答,但我希望这会有所帮助。
重新考虑设计从您尝试解决的真实问题(业务需求等)开始,并且不要尝试使用Java设计在Go中解决它。 Go没有继承,接口是它唯一的多态形式;你不能模仿动态调度"在Go中以任何合理的方式。
具体而言,就此而言:
我有两个相同界面的实现,只有一个不同 小。在这种情况下,如何最大化代码重用?我无法相信 为了在一个实现中自定义位逻辑,我必须这样做 复制粘贴所有内容,然后在我的代码中修改一小部分。
根据代码重用重新考虑您的设计,而不是类层次结构,因为没有。如果你有两个相同接口的实现,那很好! Go有接口,它们工作得很好。如果你在两个实现中都重复了一堆代码,或者a)将共享代码抽象为两个实现都可以调用的函数,或者b)如果差异真的那么小,也许它应该是具有一些简单切换逻辑的单个实现
答案 1 :(得分:5)
Go没有“类”的子类或扩展名。嵌入式类型的方法使用其原始类型接收器。在这种情况下,方法MegaDo
会在B
内提升,但在调用时,会在A
字段中调用它。 B.MegaDo()
只是B.A.MegaDo()
的语法糖。因此,当它在其接收方上调用Do()
时,它会调用A
版本,而不是B
版本。
处理此问题的更简单方法是嵌入接口。例如:
https://play.golang.org/p/ZPdK8zsy5_w
type Mega struct {
I
}
func (m Mega) MegaDo() {
m.Do()
}
func main() {
var a A
var b B
m := Mega{I: A}
m.MegaDo()
m.I = B
m.MegaDo()
}
注意:在这种情况下实际上并不需要嵌入接口,因为如果它是命名字段,MegaDo()
可以简单地调用m.i.Do()
。但是,嵌入它允许其他代码直接调用Do()
上的m
,而不知道该字段中实际嵌入了什么类型。另请注意,嵌入接口的实际结果是,按定义嵌入接口的结构也可以实现相同的接口。
此模式的实际示例:嵌入sql.DB和sql.Tx类型(QueryRow,Query,Exec等)的联合方法的DB句柄类型。该句柄的用户可以调用这些方法,而无需知道它们是否在事务的上下文中被调用。