我有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 => ... }
}
此方法无法在编译期间检查正确的类型。我怎样才能实现第一次实施? 有没有设计模式来处理这个问题?
答案 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)
并通过list
将Animal
传递给每个实例,会发生什么? foo
应该可以处理任何X1
,但它只接受Animal
,传递Cat
时会发生什么?您要求Dog
与X1
中断合同。
答案 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)是不确定的。