为什么可以在 Scala 中实例化多个特征,而不是单个特征?
Why is it possible to instantiate multiple traits in Scala, but not a single one?
假设我们有两个特征:
trait Trait1
trait Trait2
如果我尝试类似 val single = new Trait1
的操作,我会得到一个错误 error: trait Trait1 is abstract; cannot be instantiated
。但是,val twoTraits = new Trait1 with Trait2
编译。为什么会这样?
P.S。我还观察到 val single = new Trait1 {}
编译得很好。你能提供一个适当的解释吗?
从技术上讲,您不能直接实例化单个特征或多个混合特征,但编译器使用一些语法糖可以让您创建 anonymous classes扩展它们。假设我们有:
trait A
trait B
当您调用 new A with B
时,真正发生的是编译器正在创建一个混合了 A
和 B
的匿名 class。你得到:
final class $anon extends A with B
new $anon()
当您调用 new A {}
时,同样的事情也会发生。你得到一个扩展 A
:
的匿名 class
final class $anon extends A
new $anon()
唯一的区别是语法上的。从单个特征创建匿名 class 时,您至少需要使用大括号 {}
将其与 class 区分开来。也就是说,更容易辨别模板是否可以构造,或者必须包裹在一个匿名的class中才能构造。对于多个特征(甚至 class 混合特征),编译器理解它将 总是 需要首先创建一个匿名 class。
总结一下:
class C
new A {} // Anonymous class that extends A, then constructed
new A with B // Anonymous class that extends A with B, then constructed
new C // Constructed instance of class C
new C with A // Anonymous class that extends C with A, then constructed
假设我们有两个特征:
trait Trait1
trait Trait2
如果我尝试类似 val single = new Trait1
的操作,我会得到一个错误 error: trait Trait1 is abstract; cannot be instantiated
。但是,val twoTraits = new Trait1 with Trait2
编译。为什么会这样?
P.S。我还观察到 val single = new Trait1 {}
编译得很好。你能提供一个适当的解释吗?
从技术上讲,您不能直接实例化单个特征或多个混合特征,但编译器使用一些语法糖可以让您创建 anonymous classes扩展它们。假设我们有:
trait A
trait B
当您调用 new A with B
时,真正发生的是编译器正在创建一个混合了 A
和 B
的匿名 class。你得到:
final class $anon extends A with B
new $anon()
当您调用 new A {}
时,同样的事情也会发生。你得到一个扩展 A
:
final class $anon extends A
new $anon()
唯一的区别是语法上的。从单个特征创建匿名 class 时,您至少需要使用大括号 {}
将其与 class 区分开来。也就是说,更容易辨别模板是否可以构造,或者必须包裹在一个匿名的class中才能构造。对于多个特征(甚至 class 混合特征),编译器理解它将 总是 需要首先创建一个匿名 class。
总结一下:
class C
new A {} // Anonymous class that extends A, then constructed
new A with B // Anonymous class that extends A with B, then constructed
new C // Constructed instance of class C
new C with A // Anonymous class that extends C with A, then constructed