我最近发现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?
答案 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(): AnyRef
。 object 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.AA
(SSA
)的伴随对象满足SSA.apply
。
在方法中添加参数后,您将不再具有0参数apply
方法来履行该职责。
答案 2 :(得分:0)
好的,我发现了这样做的规范方法:
trait SS_Parameterised {
type AA <: AALike
def AA: Int => AnyRef
}
故事的结尾:)一个案例类重写2个声明?没问题