我有some example code我在其中声明了一个类型foo
,其中包含一些相互调用的方法(例如:foo.get
,由foo.double
和{{1}调用}})。
我有另一种类型foo.toString
,它嵌入bar
并重新定义foo
。我被迫在get
上重新定义double
和toString
,因此他们可以看到bar
(而不仅仅是bar.get
),但这些函数的主体是基本上与原版相同。
是否有更好的方法来组织此代码,以避免冗余,同时让foo.get
完成与bar
相同的接口?
注意:
foo
上声明的嵌入foo
类型的方法时,我必须仔细检查以查看{{1}上的哪些其他方法打电话给它,并确保重新定义所有这些。事实证明,很容易错过一个。foo
'以及每种类型的相似数量的互连方法。foo
调用foo
而不是foo.double
,但这似乎是有点浪费,并且意味着f.outermost.get()
的零值无效。 (另外,只有嵌入类型是结构时才有可能。)答案 0 :(得分:3)
在Go中有embedding,但没有polymorphism。如果在结构中嵌入类型,则嵌入类型的所有方法都会被提升,并且将位于包装器结构类型的method set中。但是你无法“覆盖”推广的方法。当然,您可以使用相同的名称添加自己的方法,并在包装器结构上调用该名称的方法将调用您的方法,但是如果从嵌入类型调用此方法,则不会将该方法调度到您的方法,仍将调用已定义为嵌入类型的“原始”方法。
在此处详细了解此信息:Does fragile base class issue exist in Go?此处:Go embedded struct call child method instead parent method。
看起来您只想“继承”double()
和toString()
方法(在Go中应该称为String()
),而不是get()
方法它的实现从类型到类型发生了变化。
所以基本上你应该重构一下。您的foo
类型应具有/获取提供get()
方法的值。您可以使用getter
界面捕获此内容:
type getter interface {
get() int
}
foo
实施:
type foo struct {
g getter
}
func (f foo) double() int {
return f.g.get() * 2
}
func (f foo) toString() string {
return fmt.Sprintf("%d", f.g.get())
}
嵌入bar
的{{1}}类型,仅提供“缺失”foo
:
get()
用法示例:
type bar struct {
foo
}
func (b bar) get() int {
return 69
}
输出符合预期(在Go Playground上尝试):
b := bar{}
b.foo = foo{g: b}
fmt.Println(b.double())
fmt.Println(b.toString())
使用上面的138
69
界面很不错,因为如果您需要为其添加其他方法,它将来会提供灵活性。
如果不是这种情况,而您只需要一个功能,则可以省略界面并使用功能值。
这就是它的样子:
getter
使用它:
type foo struct {
get func() int
}
func (f foo) double() int {
return f.get() * 2
}
func (f foo) toString() string {
return fmt.Sprintf("%d", f.get())
}
type bar struct {
foo
}
func (b bar) get() int {
return 69
}
输出是一样的。在Go Playground上尝试。
请注意,虽然我们使用了b := bar{}
b.foo = foo{get: b.get}
fmt.Println(b.double())
fmt.Println(b.toString())
方法(bar.get()
method value),但并不要求b.get
应该是一种方法。它可以是普通的函数值,甚至是function literal,例如:
get()
在Go Playground上试试这个。