Scala语言:集成面向对象和函数式编程的特性

时间:2021-01-20 22:52:05

简介

Scala编程语言近来抓住了很多开发者的眼球。如果你粗略浏览Scala的网站,你会觉得Scala是一种纯粹的 面向对象编程语言,而又无缝地结合了命令式和函数式的编程风格。Christopher Diggins认为:
不太久之前 编程语言还可以毫无疑义地归类成“命令式”或者“函数式”。Scala代表了一个新的语言品种,它抹平了这些人为划分的界限。
根据David Rupp在博客中的说法,Scala可能是下下一代Java。这么高的评价让人不禁想看看它到底是什么东西。
Scala有几项关键特性表明了它的 面向对象的本质。例如,Scala中的每个值都是一个对象,包括基本 数据类型(即布尔值、数字等)在内,连函数也是对象。另外,类可以被子类化,而且Scala还提供了基于mixin的组合(mixin-based composition)。
与只支持单继承的语言相比,Scala具有更广泛意义上的类重用。Scala允许定义新类的时候重用“一个类中新增的成员定义(即相较于其父类的差异之处)”。Scala称之为mixin类组合。
Scala还包含了若干函数式语言的关键概念,包括高阶函数(Higher-Order Function)、局部套用(Currying)、 嵌套函数(Nested Function)、序列解读(Sequence Comprehensions)等等。
Scala是静态类型的,这就允许它提供 泛型类内部类、甚至 多态方法(Polymorphic Method)。另外值得一提的是,Scala被特意设计成能够与Java和.NET互操作。Scala当前版本还不能在.NET上运行(虽然上一版可以-_-b),但按照计划将来可以在.NET上运行。
Scala可以与Java互操作。它用scalac这个 编译器源文件编译成Java的 class文件(即在JVM上运行的 字节码)。你可以从Scala中调用所有的Java类库,也同样可以从Java 应用程序中调用Scala的代码。用David Rupp的话来说,
它也可以访问现存的数之不尽的Java类库,这让(潜在地)迁移到Scala更加容易。
这让Scala得以使用为Java1.4、5.0或者6.0编写的巨量的Java类库和框架,Scala会经常性地针对这几个版本的Java进行测试。Scala可能也可以在更早版本的Java上运行,但没有经过正式的测试。Scala以BSD许可发布,并且数年前就已经被认为相当稳定了。
说了这么多,我们还没有回答一个问题:“为什么我要使用Scala?”Scala的设计始终贯穿着一个理念:
创造一种更好地支持组件的语言。(《The Scala Programming Language》,Donna Malayeri)
也就是说 软件应该由可重用的部件构造而成。Scala旨在提供一种 编程语言,能够统一和一般化分别来自 面向对象和函数式两种不同风格的关键概念。
藉着这个目标与设计,Scala得以提供一些出众的特性,包括:
* 面向对象风格
* 函数式风格
* 更高层的并发模型
Scala把Erlang风格的基于actor的并发带进了JVM。开发者现在可以利用Scala的actor模型在JVM上设计具伸缩性的并发 应用程序,它会自动获得 多核心处理器带来的优势,而不必依照复杂的Java线程模型来编写程序。
* 轻量级的函数语法
o 高阶
o 嵌套
o 局部套用(Currying)
o 匿名
* 与XML集成
o 可在Scala程序中直接书写XML
o 可将XML转换成Scala类
* 与Java无缝地互操作
Scala的风格和特性已经吸引了大量的开发者,比如Debasish Ghosh就觉得:
我已经把玩了Scala好一阵子,可以说我绝对享受这个语言的创新之处。
总而言之,Scala是一种函数式 面向对象语言,它融汇了许多前所未有的特性,而同时又运行于JVM之上。随着开发者对Scala的兴趣日增,以及越来越多的工具支持,无疑Scala语言将成为你手上一件必不可少的工具。
Scala与Groovy的对比
去年早些时候,一篇名为“Scala,Groovy的杀手? ”的博客对Scala和Groovy进行了对比:
Scala和Groovy之间的核心区别在于前者是静态类型的。有些人可能争辩说这使得达到 脚本化目标变得更加复杂了,而脚本化正是Groovy的动机。然而,Scala有完整的体系特征,这使Groovy看上去更像个玩具。比如,Scala有“sequence comprehensions”。该要素导致对算法的表述非常紧凑和强大。
Scala还有更多被证明是非常有用的特性,如嵌套类,currying和代数类型模式匹配。它还支持类似于JDK1.5所增加的 泛型和注解。这些还都只是冰山一角。
之后,Derek Young撰文“Scala对比Groovy:静态类型是性能的关键”。在文中他举了一个实际的例子,试图说明针对同样的算法,Scala的性能远高于Groovy。
然而,Scala并不是尽善尽美的,它也有一些明显的缺陷。Rick Hightower在最近发表的一篇博客中,尖锐地批评了Scala的语法问题:
Scala并不是更好的选择。在阅读了Scala的文档之后,我的想法是:虽然这种语言的特性听起来挺好,但是语法却让我想放弃。为什么事情非要为了不同而不同?Scala让Groovy看起来比以前更加美味可口。
憎恨是个很强烈的词。我恨Scala的语法。请不要再推进这种语法了。……Scala有好的思想吗?有。借用过来就行了……
总而言之,Scala看起来像下一个被过度宣传的语言。只需要把其精华引入到Groovy中,然后扔掉那些糟糕的语法。我最喜欢的Scala特性是推理类型和强类型。C#3.0也有这些。(我不用C#,不见得我不喜欢它的一些特性。)
Rick Hightower还建议Sun应该在Groovy上进行投资,而不是对JRuby作无谓的投资。
Groovy更像Java,更容易上手,语法也让开发者不反感。为什么Sun在JRuby上投那么多钱呢?
投资应该给Groovy。这样了解Java的开发者可以更快地学习Groovy,而且如果有工具支持他们,那么就更可能这样做。
为了说明Sun投资在Ruby上的不明智,Rick Hightower还引用了一幅统计图表来说明企业采用Ruby的趋势还是比较低的:
498)this.style.width=498;">
图1
另外,无论是Ruby、Scala还是Groovy都有对应的Web框架,且对应的框架都是用各自对应的语言编写的。这些框架分别是Rails、Lift和Grails。尽管Lift和Grails中的许多东西都从Rails借鉴来的,但是Grails对其他已有Java技术框架进行了很好的继承,这无疑会保护用户或厂商在这方面的已有投资。Grails框架参考文档中这样描述:
Grails构建在这些概念之上,并且显著地减少了在 Java平台上构建Web应用的复杂程度。不同的是,这些是建立在已确立的如Spring和Hibernate这样的Java技术之上的。
目前,Scala和Groovy两种语言都在快速发展的过程中。就目前的情况来看,Groovy的优势在于易用性以及与Java无缝衔接,Scala的优势在于性能和一些高级特性,如果在发展过程中两者能互相借鉴对方的优点来充实自身,对开发者来讲无疑是福音。正如第一篇所引用的博客作者最后提到的那样:
大家并不想看到一场殊死斗争,而是想看到更注重实效思想的Groovy团队能与更具有学术思想的Scala团队一起合作,制作出一门既强大又易用的语言。
你会将赌注押在谁身上呢?
Scala 发音为 /ˈskɑːlə, ˈskeɪlə/)是一种多范式的编程语言,设计意图是要集成 面向对象编程和 函数式编程的各种特性。

平台和许可证

Scala运行于Java平台(Java 虚拟机),并兼容现有的Java程序。它也能运行于Java ME, CLDC(Java Platform, Micro Edition Connected Limited Device Configuration)上。目前还有另一.NET平台的实现,不过该版本更新有些滞后。
Scala的编译模型(独立编译,动态类加载)与Java和C#一样,所以Scala代码可以调用Java类库(对于.NET实现则可调用.NET类库) 。
Scala包中包含了 编译器和类库,以BSD许可证发布。

发展历史

联邦理工学院洛桑(EPFL)的Martin Odersky于2001年基于Funnel的工作开始设计Scala。Funnel是把函数式编程思想和Petri网相结合的一种 编程语言。Odersky先前的工作是Generic Java和javac(Sun Java 编译器)。Java平台的Scala于2003年底/2004年初发布。.NET平台的Scala发布于2004年6月。该语言第二个版本,v2.0,发布于2006年3月。
截至2009年9月,最新版本是版本2.7.6 。Scala 2.8预计的特性包括重写的Scala类库(Scala collections library)、方法的命名参数和默认参数、包对象(package object),以及Continuation.
2009年4月,Twitter宣布他们已经把大部分后端程序从Ruby迁移到Scala,其余部分也打算要迁移。此外, Wattzon已经公开宣称,其整个平台都已经是基于Scala基础设施编写的。

特性

面向对象特性
Scala是一种纯 面向对象的语言,每一个值都是对象。对象的数据类型以及行为由类和特征(Trait)描述。类抽象机制的扩展有两种途径。一种途径是子类继承,另一种途径是灵活的混入(Mixin)机制。这两种途径能避免 多重继承的种种问题。 [1]
函数式编程
Scala也是一种函数式语言,其函数也能当成值来使用。Scala提供了轻量级的语法用以定义 匿名函数,支持高阶函数,允许嵌套多层函数,并支持 柯里化 。Scala的Case Class及其内置的模式匹配相当于函数式编程语言中常用的代数类型(Algebraic Type)。 [1]
更进一步, 程序员可以利用Scala的模式匹配,编写类似 正则表达式的代码处理XML数据。在这些情形中,顺序容器的推导式(comprehension)功能对编写公式化查询非常有用。
由于JVM不支持尾部 递归,Scala也不能完全支持尾部递归优化。不过,在简单的情况下,Scala 编译器可以把尾部递归优化成循环。
以下代码以函数式风格实现了 快速排序算法,可以与Erlang快速排序的例子做个比较:
def qsort(list: List[Int]): List[Int]=
list match{
case Nil => Nil
case pivot::tail =>
qsort(for(i <- tail if i < pivot)yield i)::: pivot :: qsort(for(i <- tail if i >= pivot)yield i)
}
静态类型
Scala是具备类型系统,通过编译时的检查,保证代码的安全性和一致性。类型系统具体支持以下特性:
泛型类,型变注释(Variance Annotation),类型继承结构的上限和下限,把类别和抽象类型作为对象成员,复合类型,引用自己时显式指定类型,视图, 多态方法。 [1]
扩展性
Scala的设计承认一个事实,即在实践中,某个领域特定的 应用程序开发往往需要特定于该领域的语言扩展。Scala提供了许多独特的语言机制,可以以库的形式轻易无缝添加新的语言结构:
任何方法可用作前缀或后缀操作符,可以根据预期类型自动构造闭包。联合使用以上两个特性,使你可以定义新的语句而无须扩展语法也无须使用宏之类的 元编程特性。 [1]
使用Scala的框架
Lift是一个开源的Web应用框架,旨在提供类似Ruby on Rails的东西。因为Lift使用了Scala,所以Lift 应用程序可以使用目前所有的Java库和Web容器。

范例

以下是用Scala编写的典型的Hello Scala中文程序:
object HelloScalachina extends Application { println("Hello, Scala中文!")}
object HelloScalachina {def main(args: Array[String]){ println("Hello, Scala中文!")}}
请注意它与Java的Hello Scala中文 应用程序有哪些相似之处。一个显著区别在于,Scala版的Hello Scala中文程序没有把任何东西标记为static,而是用object 关键字创建了一个单件。
假设该程序保存为HelloScalachina.scala文件,接下来可以通过以下命令行进行编译:
> scalac HelloScalachina.scala
若要运行:
> scala -classpath . HelloScalachina
这与编译和运行Java的“Hello Scala中文”程序是不是很像呢?事实上,Scala的编译和执行模型与Java是等效的,因而它也兼容于Java的构建工具,比如Ant.
直接使用Scala 解释器也可以运行该程序,使用选项 -i (从文件加载代码)和选项 -e (若要运行额外的代码,就得实际执行HelloScalachina对象的方法)即可:
> scala -i HelloScalachina.scala -e 'HelloScalachina.main(null)'

测试

以下是测试Scala代码的一些方式:
ScalaTest ScalaCheck,类似于Haskell的QuickCheck的一个库specs,一个用于Scala的行为驱动的开发工具库JUnit内置的Scala库SUnit已经不赞成使用,将会在2.8.0版中移除,见SUnit文档。