我打算将我们的服务器从c ++移植到Go,并且在处理基于派生类的对象列表方面存在一个问题。 我的意思是说,如果我有一个称为A的基类(或接口),并且它具有子类B和C,并且我想拥有一个通用列表,该列表可以处理类型A的列表并且是派生的。
在面向对象的语言中,我只能创建(指针)A的列表,仅此而已,就可以将对象B和C添加到列表中,因为它们的确属于A类型。但是由于Go没有继承,我对于如何有效处理此问题感到困惑。
答案 0 :(得分:0)
如前所述,您可以使用界面来执行此操作。您可以创建类型为[]Intf
的列表,其中Intf
是类型通用的接口,然后可以将实现该接口的任何类型的内容放入列表。
type A struct{}
type B struct{}
type Intf interface {
// common methods of A and B
}
func f(a Intf) {
// Here, a is A or B
}
您在处理副本还是指针时必须小心。例如:
a:=A{}
b:=B{}
x:=[]Intf{&a,&b}
f(x)
不同于:
x:=[]Intf{a,b}
f(x)
对于第一个,如果f
修改了数组元素,则变量a
和b
会被修改,因为该接口包含一个指针。对于第二个,如果f
修改了数组元素,则a
和b
不会受到影响,因为数组中的接口包含指向这些变量副本的指针。
如果说A
的接口Intf
中包含一个采用指针接收器的方法,那么您必须使用数组中所有A
实例的地址。 / p>
Go的类型系统是明确且严格的。因此,例如,您通过接口实现了多态列表,并且具有以下功能:
func f(input []Intf) {
}
func g(input Intf) {
}
假设您有以下变量:
var a []A
var b A
其中A
实现Intf
。然后:
g(b) // This is valid
f(a) // This is *not* valid
这是因为f
获得了[]Intf
,但是a
是[]A
,而不是[]Intf
。要调用f
,您必须构建一个[]Intf
:
fInput:=make([]Intf,0,len(a))
for _,x:=range a {
fInput=append(fInput,x)
}
f(fInput)
因此,如果要处理多态列表,则始终使用接口列表而不是具体类型列表是有意义的。
如果需要根据类型直接访问字段,则还可以使用类型断言:
func f(in []Intf) {
for _,x:=range in {
if a, ok:=x.(*A); ok {
a.Field=1
}
}
}