第十章 特质(trait)
Scala中一个类可以扩展一个或多个特质,与Java的接口不同的是,Scala的特质可以给出这些特性的缺省实现。
要点
- Java中,类只能扩展一个超类,可以实现任意数量的接口,但是接口只能包含抽象的方法,不能包含字段。而Scala提供“特质”而非接口,特质可以同时又抽象额方法和具体方法,而类可以实现多个特质。
- 当做接口使用的特质
- 接口中的方法不需要将方法声明为abstract,特质中未被实现的方法默认就是抽象的
- 重写特质的抽象方法时不需要给出override关键字
- 可以用with关键字来添加额外的特质
- 所有的Java接口都可以作为Scala特质使用
- 带有具体实现的特质
构造单个对象时,可以为它添加特质
trait logged { def log(msg: String) { } } class SavingsAccount extends Account with Logged { def withdraw(amount: Double) { if(amount > balance) log("Insufficient friends") else ... } ... } trait ConsoleLogger extends Logged { override def log(msg: String) { println(msg) } } val acct = new SavingAccount with ConsoleLogger
叠加在一起的特质
val acct1 = new SavingsAccount with ConsoleLogger with TimestampLogger with ShortLogger
ShortLogger 的super.log会调用TimestampLogger的log
- 特质构造顺序,构造器以如下顺序执行
- 首先调用超类的构造器
- 特质构造器在超类构造器之后、类构造器之前执行
- 特质由左到右被构造
- 每个特质中,父特质先被构造
- 如果多个特质共有一个父特质,而那个父特质已经被构造,则不会被再次构造
- 所有特质构造完毕,子类被构造
- 初始化特质中的字段
- 特质不能有构造器参数,每个特质都有一个无参数的构造器,缺少构造器参数是特质与类之间唯一的技术差别,除此以外,特质可以具备类的所有特性,比如具体的和抽象的字段,以及超类。
- 特质也能扩展类,这个类会自动成为所有混入该特质的超类。
- 当特质以如下代码定义时 this: 类型 => 它便只能被混入指定类型的子类
- Scala需要将特质翻译成JVM的类和接口。翻译过程需要注意的是,带有具体方法和字段的特质会被翻译成一个接口加一个伴生类。
第十一章 操作符
要点
- 操作符通常用来构建领域特定语言——内嵌在Scala的迷你语言
- 变量、函数、类等的名称统称为标识符
- 中置操作符可以写作: a 标识符 b,其中标识符表示一个带有两个参数的方法(一个隐式的参数和一个显式的参数),例如 1 to 10实际上是1.to(10)
- 一元操作符分为postfix和prefix
- postfix: a 标识符 等价于 a.标识符()
- prefix: + - ! ~出现在参数之前,被转换为对名为unary_操作符的方法调用。例如-a等价于a.unary_-
Scala中,所有的操作符都是左结合的,除了以冒号结尾的操作符和赋值操作符,其中用于构造列表的::操作符是右结合的。例如1::2::Nil的意思是1::(2::Nil),右结合的二元操作符是其第二个参数的方法,2::Nil的意思是Nil.::(2)
apply可以被用在伴生对象中,用来构造对象而不是显示地使用new
提取器是一个带有unapply方法的对象,unapply接受一个对象,然后从中提取值,通常是当初用来构造该对象的值。可以用于模式匹配
case Fracetion(a, b) => //匹配成功以后,匹配得到的值会被赋给a和b
每一个case class都自动有一个apply和unapply方法
- unapplySeq方法可以用来提取任意长度的值的序列