Kel*_*vin 3 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; 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?
Run Code Online (Sandbox Code Playgroud)
为什么baseFail线路出现故障,而另一条线路val没有?
错误消息也令人困惑 - 我不是试图实例化Base,只是混合它.
当你写作时new { } with Base,技术上没有任何早期定义.根据SLS 5.1.6,编译器会查找如下模式:
EarlyDefs ::= `{' [EarlyDef {semi EarlyDef}] `}' `with'
EarlyDef ::= {Annotation} {Modifier} PatVarDef
Run Code Online (Sandbox Code Playgroud)
虽然它没有明确说明当定义序列为空时会发生什么,但它似乎只是删除它们,因为在编译时val a = new { val x = 1 } with Base,你会在解析阶段之后得到类似的东西:
val a = {
final class $anon extends Base {
val x = _;
def <init>() = {
val x = 1;
super.<init>();
()
}
};
new $anon()
}
Run Code Online (Sandbox Code Playgroud)
但如果你清空括号,你只需得到:
val a = new Base()
Run Code Online (Sandbox Code Playgroud)
这是违法的new Base.
总结一下:
是匿名类,允许:
val base1 = new Base { }
Run Code Online (Sandbox Code Playgroud)
简化为new Base,这是非法的:
val baseFail = new { } with Base
Run Code Online (Sandbox Code Playgroud)
是否允许适当的早期定义(非空):
val base2 = new { val n=1 } with Base
Run Code Online (Sandbox Code Playgroud)
简化new Base with Proxy也允许:
val proxy = new { } with Base with Proxy
Run Code Online (Sandbox Code Playgroud)
new { } with Base { }也编译,但它完全相同new Base { },所以没有理由这样写.