Scala 带有SomeTrait`的早期初始值设定项'new{}失败
在使用早期初始值设定项语法时,似乎有一个微妙之处Scala 带有SomeTrait`的早期初始值设定项'new{}失败,scala,traits,anonymous-class,Scala,Traits,Anonymous Class,在使用早期初始值设定项语法时,似乎有一个微妙之处 trait Base { def callMe = "callMe" } trait Proxy { this: Base => def call = s"proxied: $callMe" } val base1 = new Base { } // non-early init works val baseFail = new { } with Base // error: trait Base is abstract; can
trait Base { def callMe = "callMe" }
trait Proxy { this: Base => def call = s"proxied: $callMe" }
val base1 = new Base { } // non-early init works
val baseFail = new { } with Base // error: trait Base is abstract; cannot be instantiated
val base2 = new { val n=1 } with Base // why does this fix the failure?
val proxy = new { } with Base with Proxy // why doesn't this fail?
为什么baseFail
行失败,而其他val
行没有失败
错误消息也令人困惑-我没有尝试实例化
Base
,只是将其混入其中。我不确定,但我能想到的关于此行为的最简单解释是,空的早期初始值设定项只是被优化掉了,因此它相当于val baseFail=newbase
和val proxy=newbase with proxy
new Base
失败并显示相同的错误消息,new Base with Proxy
合法,因为它是匿名类。如果是这样的话,我认为从技术上讲这是一个编译器错误,但相当小。当你用Base编写new{}时,从技术上讲,没有任何早期的定义。根据SLS 5.1.6,编译器查找如下模式:
EarlyDefs ::= `{' [EarlyDef {semi EarlyDef}] `}' `with'
EarlyDef ::= {Annotation} {Modifier} PatVarDef
虽然它没有明确说明当定义序列为空时会发生什么,但它似乎只是删除了它们,因为当您使用Base编译val a=new{val x=1}时,在解析阶段后会得到如下结果:
val a = {
final class $anon extends Base {
val x = _;
def <init>() = {
val x = 1;
super.<init>();
()
}
};
new $anon()
}
这是非法的,就像新基地一样
总结如下:
是一个匿名类,这是允许的
:
简化为新基
,这是非法的:
val baseFail = new { } with Base
是一个适当的早期定义(非空),允许:
val base2 = new { val n=1 } with Base
通过代理简化为新的基础,这也是允许的:
val proxy = new { } with Base with Proxy
new{}with Base{}
也可以编译,但它与new Base{}
完全相同,因此没有理由这样编写
val base2 = new { val n=1 } with Base
val proxy = new { } with Base with Proxy