[英]How can I organise this Go code that redefines methods from an embedded type to be less redundant and more maintainable?
我有一些示例代码 ,其中我声明了一个类型foo
,其中一些方法相互调用(例如: foo.get
,由foo.double
和foo.toString
)。
我有另一种类型, bar
,嵌入foo
并重新定义get
。 我被迫在bar
上重新定义double
和toString
,因此他们可以看到bar.get
(而不仅仅是foo.get
),但这些函数的主体基本上与原始函数相同。
是否有更好的方法来组织此代码,以避免冗余,同时仍然bar
履行与foo
相同的接口?
笔记:
foo
上嵌入的类型foo
我要仔细检查,看看哪些其他方法foo
调用它,并确保重新定义所有这些了。 事实证明,它很容易错过一个。 foo
',并且每种类型都有相似数量的互连方法。 foo.double
调用f.outermost.get()
而不是f.get()
,但这似乎有点浪费,意味着foo
零值无效。 (另外,只有嵌入类型是结构才有可能。) 在Go中有嵌入 ,但没有多态性 。 如果在结构中嵌入类型,则嵌入类型的所有方法都将被提升,并且将位于包装器结构类型的方法集中 。 但是你无法“覆盖”推广的方法。 当然,您可以使用相同的名称添加自己的方法,并在包装器结构上调用该名称的方法将调用您的方法,但是如果从嵌入类型调用此方法,则不会将该方法调度到您的方法,仍然会调用为嵌入式定义的“原始”方法。
在这里阅读更多相关内容: Go中是否存在脆弱的基类问题? 在这里: 转到嵌入式struct call子方法而不是父方法 。
看起来你只想“继承” 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())
}
还有一个嵌入foo
的bar
类型,只提供“缺少”的get()
:
type bar struct {
foo
}
func (b bar) get() int {
return 69
}
用法示例:
b := bar{}
b.foo = foo{g: b}
fmt.Println(b.double())
fmt.Println(b.toString())
输出与预期一致(在Go Playground上尝试):
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
}
并使用它:
b := bar{}
b.foo = foo{get: b.get}
fmt.Println(b.double())
fmt.Println(b.toString())
输出是一样的。 在Go Playground尝试一下。
请注意,虽然我们使用了bar.get()
方法( b.get
方法值 ),但并不要求get()
应该是一个方法。 它可以是普通的函数值,甚至是函数文字 ,例如:
b := bar{foo: foo{get: func() int { return 69 }}}
fmt.Println(b.double())
fmt.Println(b.toString())
在Go Playground尝试这个。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.