在Scala中,内部案例类如何始终覆盖方法?

时间:2019-04-22 21:36:26

标签: scala inheritance override case-class

我最近发现Scala编译器具有用于case类的有趣功能:由于它既生成类又生成对象签名,因此如果将其定义为内部类,则可以使用它来覆盖以下类型的抽象类型定义和函数定义:它的超类具有最少的样板代码,下面是一个示例:

object InnerCaseClassOverridingBoth {

  trait AALike

  trait SS {
    type AA <: AALike
    def AA(): AnyRef
  }

  trait SS_Clear extends SS {
    def AA(): AnyRef
  }

  class SSA extends SS_Clear {
    case class AA() extends AALike
  }
  object SSA extends SSA {}
}

这将编译而没有任何错误。但是,快捷方式在此处停止,如果对函数定义def AA进行了参数化,则内部案例类和内部对象都无法覆盖它:内部对象的apply函数不会自动扩展为外层方法:

  trait SS_Parameterised extends SS {
    def AA(ii: Int): AnyRef
  }

  class SSB extends SS_Parameterised {
    case class AA(ii: Int) extends AALike
  }
  object SSB extends SSB {}

这给出了一个错误:

class SSB needs to be abstract, since method AA in trait
SS_Parameterised of type (ii: Int)AnyRef is not defined
    class SSB extends SS_Parameterised {

我的问题是,在这种情况下是否有捷径?为什么Scala编译器设计为链接情况1但不链接情况2?

3 个答案:

答案 0 :(得分:4)

它并不是专门设计的;或者,但不是您所认为的方式。您并没有使用构造def AA()的方法来覆盖AA,而是使用object AA本身来覆盖它。注意

trait T {
   type I <: AnyRef
   def I(): AnyRef
}
object O extends T {
   case class I(val i: Int)
}

这很好。

> (O: T).I()
I
> (O: T).I().getClass
class O$I$
> O.I(5)
I(5)
> O.I(5).getClass
class O$I

主要的设计选择是“ object s可以覆盖无参数def s”({{1} s,val s也可以,当然,没有-param var s和“ def es自动生成case class s”。 “内部object使用其构造函数覆盖其外部类中同名的方法”不是Scala的规则之一。 case class包含一个object O和一个case class I,摘要object I被覆盖以返回所说的def I(): AnyRefobject I的内容无关紧要,因为object I只需要返回一个def I(),这意味着没有限制。

AnyRef

然后失败。 trait U { type I <: AnyRef def I(i: Int): AnyRef } object P extends U { case class I(i: Int) } 包含一个object P和一个关联的case class I,但它还需要一个object I,它缺少它。

答案 1 :(得分:1)

我猜想这与apply在案例类中扮演的角色有关。参见Case Class default apply method SSA通过SS_Clear.AASSA)的伴随对象满足SSA.apply

在方法中添加参数后,您将不再具有0参数apply方法来履行该职责。

答案 2 :(得分:0)

好的,我发现了这样做的规范方法:

  trait SS_Parameterised {
    type AA <: AALike
    def AA: Int => AnyRef
  }

故事的结尾:)一个案例类重写2个声明?没问题