Scala中多种性状的混合

Scala中多种性状的混合,scala,mixins,traits,Scala,Mixins,Traits,快速说明:教程中的示例 假设我有学生、工人、低收入和年轻的特点 我如何才能声明一个类(而不是实例),一个大学生,具有所有这些特征 注:我知道最简单的情况,例如有一个或两个特征的大学生: class CollegeStudent extends Student with Worker 这很简单,当声明一个类时,您只需根据需要经常使用“with”关键字 class CollegeStudent extends Student with Worker with Underpaid with Youn

快速说明:教程中的示例

假设我有学生、工人、低收入和年轻的特点

我如何才能声明一个类(而不是实例),一个大学生,具有所有这些特征

注:我知道最简单的情况,例如有一个或两个特征的大学生:

class CollegeStudent extends Student with Worker

这很简单,当声明一个类时,您只需根据需要经常使用“with”关键字

class CollegeStudent extends Student with Worker with Underpaid with Young
如果某个特性改变了类的行为,那么特性的顺序可能很重要,这完全取决于您使用的特性

此外,如果您不想拥有一个始终使用相同特征的类,您可以稍后使用它们:

class CollegeStudent extends Student
new CollegeStudent with Worker with Underpaid with NotSoYoungAnymore

我认为非常重要的是,不仅要解释语法,还要解释特征的顺序扮演着什么角色。我发现杰森·斯沃茨(第177页)的解释很有启发性

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

  • 在这种情况下,扩展具有相同字段名的多个trait将无法编译,这与“扩展类并提供自己的方法版本但未能添加覆盖关键字”完全相同

因为它决定了遗传树的形状,所以线性化顺序确实是一个非常重要的问题。例如,
类D用B和C扩展了A(其中A是类,B是类)
C是特征)将变成
类D扩展C扩展B扩展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 }
调用
newd()
将使REPL打印以下内容:

 D->C->B->A->Base

它完美地反映了线性化遗传图的结构。

改变行为意味着调用一个在多个trait中实现并具有相同名称的trait方法。因此,根据特征的顺序,它将调用该方法。