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