在Scala中混合多个特征

Dan*_*iro 52 scala traits mixins

快速说明:Scala for Java Refugees第5部分:特征和类型教程中的示例.

假设我有学生,工人,薪水不足和年轻的特征.

我如何声明具有所有这些特征的类(不是实例),CollegeStudent?

注意:我知道简单的案例,例如具有一个或两个特征的CollegeStudent:

class CollegeStudent extends Student with Worker
Run Code Online (Sandbox Code Playgroud)

Ale*_*olz 101

这很容易,在声明一个类时,你只需要经常使用"with"关键字

class CollegeStudent extends Student with Worker with Underpaid with Young
Run Code Online (Sandbox Code Playgroud)

如果特征改变了类的行为,那么特征的顺序可能很重要,这一切都取决于你正在使用的特征.

此外,如果您不希望有一个总是使用相同特征的类,您可以在以后使用它们:

class CollegeStudent extends Student
new CollegeStudent with Worker with Underpaid with NotSoYoungAnymore
Run Code Online (Sandbox Code Playgroud)


fr_*_*lio 11

我认为不仅要解释语法,而且要解释特征的排序发挥作用,这一点非常重要.我在Jason Swartz的Learning Scala(第177页)中找到了解释,非常有启发性.

  • Scala类可以一次扩展多个traits,但JVM类只能扩展一个父类.Scala编译器通过创建" 每个特征的副本以形成类和特征的高,单列层次结构 "来解决这个问题,这个过程称为线性化.

  • 在这种情况下,扩展具有相同字段名称的多个特征将无法编译,完全相同" 就像您正在扩展一个类并提供您自己的方法版本但未能添加覆盖关键字 ".

由于它确定了继承树的形状,线性化顺序确实是一个非常重要的问题.例如,class D extends A with B with C(其中A是一个类,B和C是特征)将成为class D extends C extends B extends A.同样来自本书的以下几行完美地说明了这一点:

trait Base { override def toString = "Base" }
class A extends Base { override def toString = "A->" + super.toString }
trait B extends Base { override def toString = "B->" + super.toString }
trait C extends Base { override def toString = "C->" + super.toString }
class D extends A with B with C { override def toString = "D->" + super.toString }
Run Code Online (Sandbox Code Playgroud)

调用new D()将使REPL打印如下:

 D->C->B->A->Base
Run Code Online (Sandbox Code Playgroud)

这完美地反映了线性化继承图的结构.