简体   繁体   English

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

[英]Scala override method with subclass as parameter type

I have a trait A which has a method def fun1( b:B ):C I want A 's subclass implement B with more detailed type: 我有一个trait A有一个方法def fun1( b:B ):C我想要A的子类工具B有更详细的类型:

Here is the code: 这是代码:

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{
}

I hope A 's subclass can be declared as below 我希望A的子类可以声明如下

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


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

However, the compiler will complain that X1 overrides nothing . 但是,编译器会抱怨X1 overrides nothing I have to manually match detailed B 's type, like below. 我必须手动匹配详细的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 => ... }
}

This method cannot check the correct type during compiling. 此方法无法在编译期间检查正确的类型。 How can I achieve the first implementation? 我怎样才能实现第一次实施? Is there any design pattern to handle this problem? 有没有设计模式来处理这个问题?

A similar question is C# Override method with subclass parameter 类似的问题是C#Override方法和子类参数

You can do this with a generic type parameter. 您可以使用泛型类型参数执行此操作。

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

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

You cannot refine the parameter types of an inherited method, because methods/functions are contravariant over them. 您无法优化继承方法的参数类型,因为方法/函数对它们是逆变的。

Consider this simplified example: 考虑这个简化的例子:

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)

This doesn't compile, but let's pretend it does for a moment. 这不会编译,但让我们暂时假装它。 If we need to iterate through the list and pass an Animal to each instance via foo , what happens? 如果我们需要遍历list并通过fooAnimal传递给每个实例,会发生什么? X1 is supposed to be able to handle any Animal , but instead it only accepts a Cat , what would happen when passing a Dog , instead? X1应该能够处理任何Animal ,但它只接受一只Cat ,当传递一只Dog时会发生什么? You're asking X1 to break its contract with A . 你要求X1打破与A合同。

You can't override to a more specific type. 您无法覆盖更具体的类型。 You can overload (removing the override), when creates an additional method for the more specific type. 在为更具体的类型创建其他方法时,您可以重载(删除覆盖)。 The most specific method will be called based on the actual param passed. 将根据传递的实际参数调用最具体的方法。

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

In this case, passing a B1 executes the fun1 in X1, passing any other B executes the fun1 in A. 在这种情况下,传递B1执行X1中的fun1,传递任何其他B执行在A中的fun1。

Allowing this type of override would essentially prevent X1 from taking a B as a parameter, only accepting a B1. 允许这种类型的覆盖基本上会阻止X1将B作为参数,仅接受B1。 This is in direct conflict with the method declared and defined by Trait A and can't override it. 这与Trait A声明和定义的方法直接冲突,无法覆盖它。 If the override was allowed, then x1.fun1(b:B) is indeterminate. 如果允许覆盖,则x1.fun1(b:B)是不确定的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM