【问题标题】:Scala override method with subclass as parameter type以子类为参数类型的 Scala 覆盖方法
【发布时间】:2017-02-03 02:39:18
【问题描述】:

我有一个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

【问题讨论】:

    标签: scala design-patterns overriding


    【解决方案1】:

    您可以使用泛型类型参数来做到这一点。

    trait A[T <: B] {
       def fun1( t:T ):C
    }
    
    class X1 extends A[B1]{
        override def fun1(b:B1):C1 = ...
    }
    

    【讨论】:

    • 你也可以使用抽象类型。特征 A { type T <: b ...>
    【解决方案2】:

    你不能细化继承方法的参数类型,因为方法/函数是逆变的。

    考虑这个简化的例子:

    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 并通过fooAnimal 传递给每个实例,会发生什么? X1 应该能够处理任何Animal,但它只接受Cat,当传递Dog 时会发生什么,而不是?你要求X1 解除与A 的合同。

    【讨论】:

    • 最好使用Unit以外的返回类型,因为在这种情况下有一个合理的答案:什么都不做。
    【解决方案3】:

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

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

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

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

    【讨论】:

    • 泛型是一种选择,但是 fun1 将只处理更具体的类型,而不是抽象类型。 (除非也在 trait 中定义)
    猜你喜欢
    • 2012-01-08
    • 2015-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 2019-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多