我有一个XY类型,它有各种字段和方法(几十个)。
type XY struct {
Name string
SomeValue int
...
}
func (xy *XY) Do1() { ... }
func (xy *XY) Do2() { ... }
func (xy *XY) Do3() { ... }
...
现在我想定义一个嵌入XY的第二种类型,保留所有字段和方法。但我确实想修改一些功能。
type AB struct {
XY
}
func (ab *AB) Do2() { ... }
到目前为止一切顺利。现在我想将AB传递给一个带XY的函数。
func SomeFunc(xy *XY) { ... }
这是我绊倒的地方,没有多态性。
我可以将*AB.XY
传递给函数,但不再使用AB的Do2函数了。我可以为它创建一个接口,这可能是预期的方式,但如果SomeFunc需要接近XY的所有函数,比如几乎所有字段的getter,我基本上需要创建一个XY的副本,作为接口(可能的用例:我在服务器上,必须以特定方式向客户端发送值)。我不想只使它成为一个接口,因为我必须重新定义所有使用该接口的类型的所有字段和函数。
我可以想到这个问题的解决方案,例如使Do2成为一个闭包,根据“主机”类型或XY中的枚举字段设置,并根据该“类型”变量更改Do2的行为,或者在SomeFunc中使用反射和interface{}
,但是我我想知道Go中的“正确”方式是什么。即使你有很多功能,你如何以最有效的方式做到这一点?
答案 0 :(得分:5)
在Go中执行此操作的正确方法是使用接口。创建Do1
,Do2
等界面,并使SomeFunc与界面类型一起使用。
答案 1 :(得分:4)
就像@ Ainar-G所说,使用界面是这种行为的正确方法,例如:
type Doer interface {
Do1()
Do2()
}
func (*S1) Do1() {
println("S1.Do1")
}
func (*S1) Do2() {
println("S1.Do2")
}
type S2 struct{ S1 }
func (*S2) Do1() {
println("S2.Do1")
}
func DoIt(d Doer) {
d.Do1()
d.Do2()
// you can use a type switch for specific corner cases, or implement a MarshalJson (or similar) interface for you types)
switch v := d.(type) {
case *S1:
println("Special case for S1", v)
case *S2:
println("Special case for S2", v)
}
}