Scala覆盖方法,子类为参数类型

时间:2017-02-02 18:14:20

标签: scala design-patterns override

我有trait A,其方法为def fun1( b:B ):C 我希望A的子类实现B具有更详细的类型:

以下是代码:

trait B
trait C

trait A {
  def fun1( b:B ):C
}

class B1 extends B{
}

class B2 extends B{
}


class C1 extends C{
}

class C2 extends C{
}

我希望A的子类可以声明为

class X1 extends A{
    override def fun1(b:B1):C1 = ...
}


class X2 extends A{
    override def fun1(b:B2):C2 = ...
}

然而,编译器会抱怨X1 overrides nothing。 我必须手动匹配详细的B类型,如下所示。

class X1 extends A{
    override def fun1(b:B):C = b match {case x:B1 => ... }
}


class X2 extends A{
    override def fun1(b:B2):C2 = b match {case x:B2 => ... }
}

此方法无法在编译期间检查正确的类型。我怎样才能实现第一次实施? 有没有设计模式来处理这个问题?

类似的问题是C# Override method with subclass parameter

3 个答案:

答案 0 :(得分:4)

您可以使用泛型类型参数执行此操作。

trait A[T <: B] {
   def fun1( t:T ):C
}

class X1 extends A[B1]{
    override def fun1(b:B1):C1 = ...
}

答案 1 :(得分:2)

您无法优化继承方法的参数类型,因为方法/函数对它们具有逆变性。

考虑这个简化的例子:

sum = tot.reduce((a, n) => (a + Number(n)), 0);

这不会编译,但让我们暂时假装它。如果我们需要遍历trait A { def foo(b: Animal): Unit } trait Animal class Cat extends Animal class Dog extends Animal class X1 extends A { def foo(b: Cat): Unit } class X2 extends A { def foo(b: Dog): Unit } val list: List[A] = List(new X1, new X2) 并通过listAnimal传递给每个实例,会发生什么? foo应该可以处理任何X1,但它只接受Animal,传递Cat时会发生什么?您要求DogX1中断合同。

答案 2 :(得分:1)

您无法覆盖更具体的类型。在为更具体的类型创建其他方法时,您可以重载(删除覆盖)。将根据传递的实际参数调用最具体的方法。

class X1 extends A{
  def fun1(b:B1):C1 = ...
}

在这种情况下,传递B1执行X1中的fun1,传递任何其他B执行A中的fun1。

允许这种类型的覆盖基本上会阻止X1将B作为参数,仅接受B1。这与Trait A声明和定义的方法直接冲突,并且无法覆盖它。如果允许覆盖,则x1.fun1(b:B)是不确定的。