如何处理多态对象

时间:2019-11-25 02:24:35

标签: oop go polymorphism

我打算将我们的服务器从c ++移植到Go,并且在处理基于派生类的对象列表方面存在一个问题。 我的意思是说,如果我有一个称为A的基类(或接口),并且它具有子类B和C,并且我想拥有一个通用列表,该列表可以处理类型A的列表并且是派生的。

在面向对象的语言中,我只能创建(指针)A的列表,仅此而已,就可以将对象B和C添加到列表中,因为它们的确属于A类型。但是由于Go没有继承,我对于如何有效处理此问题感到困惑。

1 个答案:

答案 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修改了数组元素,则变量ab会被修改,因为该接口包含一个指针。对于第二个,如果f修改了数组元素,则ab不会受到影响,因为数组中的接口包含指向这些变量副本的指针。

如果说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
      }
   }
}