Scala的Trait:可以包含代码的接口

开发 后端
本文介绍了Scala的Trait。除了从父类集成代码外,Scala中的类还允许从一个或者多个traits中导入代码。 对于Java程序员来说理解traits的最好方法就是把他们当作可以包含代码的接口。

本文源自Michel Schinz和Philipp Haller所写的A Scala Tutorial for Java programmers,由Bearice成中文。第一篇为Scala简单做了一下入门,第二篇描述Scala对象,第三篇对Scala类做了一些介绍。第四篇介绍了Scala的模式匹配。下面这部分介绍Scala的Trait,直译过来就是特性/特征的意思。

51CTO编辑推荐:Scala编程语言专题

7 Scala Trait

除了从父类集成代码外,Scala中的类还允许从一个或者多个traits中导入代码。

对于Java程序员来说理解traits的最好方法就是把他们当作可以包含代码的接口(interface)。在Scala中,当一个类继承一个trait时,它就实现了这个trait的接口,同时还从这个trait中继承了所有的代码。

让我们通过一个典型的实例来看看这种trait机制是如何发挥作用的:排序对象。能够比较若干给定类型的对象在实际应用中是很有用的,比如在进行排序时。在Java语言中可以比较的对象是通过实现Comparable接口完成的 。在Scala中我们可以通过吧Comparable定义为trait来做的比Java好一些。我们吧这个trait叫做Ord。

在比较对象时,一下六种关系通常使用率最高:小于、小于等于、等于、不等于、大于等于、大于。但是把他们都定义一次无疑是很没用而且繁琐的。尤其是六种关系中的四种其实是可以通过其他两种关系导出的。例如给定等于和小于的定义后就可以推导出其他的定义。于是在Scala中,这些推导可以通过下面这个trait实现:

trait Ord {
       
def < (that: Any): Boolean
       
def <=(that: Any): Boolean = (this < that) || (this == that)
       
def > (that: Any): Boolean = !(this <= that)
       
def >=(that: Any): Boolean = !(this < that)
}

这个定义在建立了一个叫做与Java中的 Comparable 等效的叫做 Ord的类型的同时还实现了使用抽象的一种关系推导其他三种的接口。比较相等性的方法没有出现是由于他已经默认存在于所有对象中了。

上面使用的叫做Any的类型表示了Scala中所有类的共同超类。事实上它就等于Java语言中的Object。

要使的一个类可以被比较,就需要可以比较他们是否相等或者大小关系,而这些都混合在上面的类Ord中了。现在我们来写一个Date类来表示格利高里历中的日期。这个日期由年、月、日三个部分组成,每个部分都可以用一个整数表示。所有我们就得出了下面这个定义:

class Date(y: Int, m: Int, d: Int) extends Ord {
       
def year = y
       
def month = m
       
def day = d
       
override def toString(): String = year + "-" + month + "-" + day
}

注意在类名后出现的extends Ord。这表示了这个类继承了Ord这个trait。

然后我们重新定义了equals这个从Object继承来的方法,好让他能够正确的比较我们日期中的每个部分。原来的equals函数的行为与Java中的一样,是按照对象的指针进行比较的。我们可以得出下面的代码。

override def equals(that: Any): Boolean =
that
.isInstanceOf[Date] && {
        val o
= that.asInstanceOf[Date]
        o
.day == day && o.month == month && o.year == year
}

这个函数使用了预定义函数 isInstanceOf 和asInstanceOf 。第一个isInstanceOf 类似Java中的 instanceof :当且仅当对象是给定类型的实例时才返回true。第二个 asInstanceOf 对应Java中的类型转换操作:当对象是给定类型的子类时转换,否则抛出ClassCastException。

最后我们还需要定义测试小于关系的函数,如下面所示。这个函数使用了预定义的函数error ,它可以使用给定字符串抛出一个异常。

def <(that: Any): Boolean = {
       
if (!that.isInstanceOf[Date])
                error
("cannot compare " + that + " and a Date")
        val o
= that.asInstanceOf[Date] (year < o.year) ||
               
(year == o.year && (month < o.month ||
               
(month == o.month && day < o.day)))
}

以上就是Data的完整定义了。这个类的实例既可以作为日期显示,也可以进行比较。而且他们都定义了6种比较操作:其中两种 : equals和< 是我们直接定义的,而其他的是从Ord中继承的。

Scala Traits 的应用远不止于此,不过更加深入的讨论不再本文的讨论范围内。

下一篇文章将是这个介绍的最后一部分,讲述Scala的泛型。

【相关阅读】

  1. Scala的模式匹配和条件类
  2. Scala类:复数类,无参方法,继承和覆盖
  3. 万物皆对象:介绍Scala对象
  4. Scala入门:Scala例子,以及如何与Java交互
  5. Scala开发环境搭建与资源推荐
责任编辑:yangsai 来源: Google Code
相关推荐

2017-02-28 15:48:11

Scala Trait设计模式框架

2013-12-04 14:19:40

JavaScript代码重用

2009-07-22 07:45:00

Scala代码重复

2011-03-18 19:37:38

Eventable接口QtWidget

2011-06-28 11:05:19

Qt QWidget Eventable

2023-11-29 13:59:00

trait定义接口

2019-11-08 09:20:57

代码开发工具

2020-10-31 17:33:18

Scala语言函数

2009-07-08 12:43:59

Scala ServlScala语言

2009-11-10 17:23:36

ScalaJDBCDAO

2010-09-14 15:34:41

Scala

2009-07-22 07:47:00

Scala客户代码

2009-12-29 10:19:15

ADSL代码表

2010-01-26 15:32:43

Scala用法错误

2009-11-16 17:04:46

Inside Scal

2009-09-28 11:42:21

KestrelScala

2009-07-21 17:16:34

Scala函数式指令式

2009-10-19 11:26:08

Scala循环数组

2009-07-22 07:42:00

Scala偏应用函数

2009-07-21 16:58:31

Scala变量范围
点赞
收藏

51CTO技术栈公众号