特质是Scala中一个很重要的特性。
更灵活的接口
Scala的特质(trait)定义和class几乎相同,只是trait不能的构造不能包含参数。
trait TraitClassA {
def doSomething() {
println("call A");
}
}
trait TraitClassB {
def doSomething() {
println("call B");
}
}
在使用trait的时候,可以用extend
或者with
。with
的方式成为混入(mixin)。用户可以with任意多个特质。这会让你想起接口(Interface)。
class A extends B with TraitClassA with TraitClassB {
...
}
Trait可以看做是更灵活,更丰富的接口。和Java中接口不同的是,Trait可以包含成员和方法的实现。这样做的好处需要某个trait就拿来用,而不需要重复实现接口。trait和混入的类是正交的。
举例说明,在Java中,定义一个Rational类就需要重写多个比较的方法。
class Rational(n: Int, d: Int) {
// ...
def < (that: Rational) =
this.numer * that.denom > that.numer * this.denom
def > (that: Rational) = that < this
def <= (that: Rational) = (this < that) || (this == that)
def >= (that: Rational) = (this > that) || (this == that)
}
而如果使用trait,这些比较的方法就可以封装在Ordered这个特质中(注意到这里使用到了类型参数[Rational])。以后所有需要实现比较特质的类,它只要实现compare方法。
class Rational(n: Int, d: Int) extends Ordered[Rational] {
// ...
def compare(that: Rational) =
(this.numer * that.denom) - (that.numer * this.denom)
}
而在使用的时候,你还是可以使用>
,<=
这样的方法,因为它们已经在Ordered特质中得到了实现。
值得注意的是,Java8中也借鉴了类似的方式。现在你可以在Java的接口中定义默认的实现了。但是它的限制还是很多。对于Java8一些新特性和Scala的比较,今后会专门讲。
堆叠和线性化
在下面的例子里,我们定义了带时间戳的日志和截断过长的的日志,这两个特质。
// 带时间戳的日志
trait TimestampLogger extends Logged {
override def log (msg: String) {
super.log(new java.util.Date() + " " + msg)
}
}
// 截断过长的的日志
trait ShortLogger extends Logged {
val maxLength = 20
override def log(msg: String) {
super.log(
if (msg.length <= maxLength) msg
else msg.substring(0, maxLength - 3) + "...")
}
}
我们的应用就可以混入这两个特质。
class myApp with TimestampLogger with ShortLogger
你也许觉得trait和C++中的多继承很像。但是它们有着根本的区别。在多继承的框架里,你必须指定哪个super被调用(比如通过虚函数)。这样,在上面的例子中,只有一个log方法会调用。而trait恰恰可以堆叠多个特性,每个log都会被调用。这才符合多个特质的语义。
注意到混入是有顺序的,基本上可以认为是最右边的先调用。在更复杂的情景中,Scala使用了线性化的方式,将复杂的继承图映射到一条线上,以保障多个特质执行的顺序。
使用原则
什么时候使用特质呢?
- 不需要复用的,或者执行效率非常关键,考虑使用具体类。
- 会在多个不太相关的类中使用,考虑使用特质。
- 继承自Java的代码,或者希望Java client以后调用,使用抽象函数。
- 不太确定使用哪种方式,考虑先使用特质,以后再调整。
使用特质的一个重要原则就是保持traits简短并且是正交的。不要把分离的功能混在一个trait里,考虑将最小的相关的意图放在一起。例如,想象一下你要做一些IO的操作:
trait IOer {
def write(bytes: Array[Byte])
def read(n: Int): Array[Byte]
}
分离两个行为:
trait Reader { def read(n: Int): Array[Byte] }
trait Writer { def write(bytes: Array[Byte]) }
可以将它们以混入的方式实现一个
IOer : new Reader with Writer...
接口最小化促使更好的正交性和更清晰的模块化。
相关推荐
1.var,val和def三个关键字之间的区别 2.trait(特质)和abstract class(抽象类)的区别 3.object和class的区别 4.c
3.Scala 基础 4.控制结构和函数 5.数据结构 6.模式匹配 7.高阶函数 8.类 9.对象 10.包和引用 11.继承 12.特质 13.注解 14.类型参数 15.隐式转换 16.文件和正则表达式 17.高级类型 18.并发编程 Akka
目录如下 Scala简介&快速入门 基础语法 ... 特质 嵌套类 类型约束 Scala数据结构之集合 函数式编程高级 隐式转换和隐式值 偏函数 高阶函数 闭包closure 柯里化函数 控制抽象 递归高级 Akka 介绍
scala基础语法,语法基础,控制结构和函数,scala数组相关操作,映射和元组,类,对象,继承,文件和正则表达式,特质,操作符,高阶函数,集合,样式匹配和样例类。
第1章 基础 A1 1 1.1 Scala解释器 1 1.2 声明值和变量 4 1.3 常用类型 5 1.4 算术和操作符重载 7 1.5 关于方法调用 8 1.6 apply方法 9 1.7 Scaladoc 11 练习 16 第2章 控制结构和函数 A1 19 2.1 条件...
11.列表的常用操作之基础操作 12.列表的常用操作之扁平化 13.列表的常用操作之拉链与拉开 14.列表的常用操作之转换字符串 15.列表的常用操作之求并集,交集,差集 16.创建不可变集 17.不可变集的常见操作 18....
scala基础语法,字符串,数值,控制结构,类和属性,方法,对象,包和导入,特质,函数式编程,集合。列表,数组,映射,文件和进程,Actors和并发,命令行执行,
scala_core_programming_1 O'Reilly Scala编程基础知识:方法,类,特质
· Scala基础入门 · 函数式编程 · 数据结构 · 面向对象编程 · 模式匹配 · 高阶函数 · 特质 · 注解&类型参数 · 隐式转换 · 高级类型 · 案例实操 Spark Core · 安装部署 · RDD概述 · 编程...
Scala训练营作业已完成的任务: 1.基础知识 2.类和特质 3,控制结构 4,数据结构/集合 5日 6,SBT 7,隐含 8.香港电话 9,错误处理