码迷,mamicode.com
首页 > 其他好文 > 详细

Scala中的特质详解

时间:2015-10-04 00:26:56      阅读:2012      评论:0      收藏:0      [点我收藏+]

标签:

     Scala中的特质与Java中的接口是比较类似的,但是Scala中的特质可以同时拥有抽象方法和具体方法,而类可以实现多个特质。下面我们详细讲解Scala中的特质这个强大的功能。

1. 把特质当作接口使用

我们定义一个trait,如下所示:

1 trait Logger {
2   def log(msg: String)
3 }

需要注意的是trait中未被实现的方法默认是抽象方法,因此不需要在方法前加abstract。

子类ConsoleLogger对Logger的实现,如下所示:

1 class ConsoleLogger extends Logger {
2   def log(msg: String): Unit = {
3     println(msg)
4   }
5 }

需要注意两点,一是实现时用的extends而不是implements;二是不需要在方法前写override关键字。

当我们需要的特质不止一个的时候,可以使用with关键字来添加其它的特质,如下所示:

1 class ConsoleLogger extends Logger with Cloneable with Serializable

我们使用Java类库中的Cloneable和Serializable接口作为特质,需要说明的是所有Java接口都可以作为Scala特质使用。

 

2. 带有具体实现的特质

带有具体方法的ConsoleLogger特质,如下所示:

1 trait Logger {
2   def log(msg: String): Unit = {
3     println(msg)
4   }
5 }

现在我们调用ConsoleLogger特质中的log(),如下所示:

1 class SavingsAccount extends Account with ConsoleLogger {
2   def withdraw (amount: Double): Unit = {
3     if (amount > balance)
4       log("Insufficient funds")
5     else
6       balance -= amount
7   }
8   ...
9 }

本质来说,就是SavingsAccount类混入了ConsoleLogger特质的功能,但是这样也存在一个不好的地方,那就是当特质发生改变时,所有混入了该特质的类都必须重新编译。

 

3. 带有特质的对象

我们定义Logged特质,如下所示:

1 trait Logged {
2   def log(msg: String): Unit = {
3   }
4 }

虽然Logged特质带了一个具体方法log(),但是该方法什么都不做。

我们在类SavingsAccount中使用Logged特质,如下所示:

1 class SavingAccount extends Account with Logged {
2   def withdraw (amount: Double): Unit = {
3     if (amount > balance)
4       log("Insufficient funds")
5     else
6       balance -= amount
7   }
8   ...
9 }

貌似上面的代码毫无意义,但是我们可以在构造具体对象的时候混入一个更好的实现,如下所示:

1 trait ConsoleLogger extends Logged {
2   override def log(msg: String): Unit = {
3     println(msg)
4   }
5 }

我们在构造对象acct的时候加入ConsoleLogger特质,如下所示:

1 val acct = new SavingsAccount with ConsoleLogger

 

4. 叠加在一起的特质

我们可以为类或对象添加多个互相调用的特质,并且调用从最后一个特质执行。这有什么用处呢?主要用于需要分阶段加工处理某个值的场景。

假设我们想给所有的日志消息添加时间戳,如下所示:

1 val acct = new SavingsAccount with ConsoleLogger
2 
3 trait TimestampLogger extends Logged {
4   override def log(msg: String): Unit = {
5     super.log(new java.util.Data() + " " + msg)
6   }
7 }

同样地,假设我们想要截断过于冗长的日志消息,如下所示:

1 trait ShortLogger extends Logged {
2   val maxLength = 15
3   override deg log (msg: String) {
4     super.log (
5       if (msg.length <= maxLength) msg else msg.substring(0, maxLength - 3) +
6         "...")
7   }
8 }

特别注意的是,super.log并不像类那样拥有相同的含义,当然如果含义相同,那么这些特质毫无用处,因为这些特质扩展的Logged特质中的log()什么也不做。实际上,super.log调用的是特质层级中的下一个特质,具体是哪一个,要根据特质添加的顺序来决定。我们会通过举例子来加以说明顺序的作用,如下所示:

1 val acct1 = new SavingsAccount with ConsoleLogger with TimestampLogger with ShortLogger
2 val acct2 = new SavingsAccount with ConsoleLogger with ShortLogger with TimestampLogger

如果执行第一条语句,我们会得到消息Sun Feb 06 17:45:45 ICT 2011 Insufficient...这说明ShortLogger中的log()首先被执行,然后它的super.log调用的是TimestampLogger。

如果执行第二条语句,我们会得到消息Sun Feb 06 1...这说明TimestampLogger中的log()首先被执行,然后它的super.log调用的是ShortLogger,其结果在之后被截断。

 

5. 在特质中重写抽象方法

 

6. 当做富接口使用的特质

 

7. 特质中的具体字段

 

8. 特质中的抽象字段

 

9. 特质构造顺序

 

10. 初始化特质中的字段

 

11. 扩展类的特质

 

参考文献:

[1] 快速了解Scala技术栈:http://www.infoq.com/cn/articles/scala-technology/

[2] 《快学Scala》

[3] 快学Scala第十章特质课后习题解答:http://css.gxzj.com.cn/News.aspx?id=383960

Scala中的特质详解

标签:

原文地址:http://www.cnblogs.com/shengshengwang/p/4853985.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!