1、Ruby 高手点评 Scala 编程语言十大绝招(1)2009-07-21 10:04 司马牵牛 51CTO.com 我要评论(1) 字号:T | T本文作者是一位资深的 Ruby 程序员。在使用过从 Pascal 到 Ruby 和 Groovy 等一系列语言后,这位程序员发现,Scala 编程语言有着很多强大之处,以至于他决定投身于 Scala 之中了。AD: 【51CTO 精选译文】几个月前,我开始使用 Scala。我用过的编程语言还有 Pascal、 C、C+ 、Java、PHP、Ruby 和 Groovy,但是,与所有那些我用过的语言相比,我发觉 Scala 是一门与众不同的语言。我是
2、在看到 Twitter 上关于 Ruby 和 Scala 讨论之后,才开始我的 Scala 编程之旅的。现在,使用 Scala 编程已经几个月了,关于 Scala 我有两点想法,虽然类似的想法已广为人知,但我仍很想与你们分享:51CTO 编辑推荐:Scala 编程语言专题Scala 的确很棒。我的确认为计算机学院应该开一门 Scala 的语言课程。在这篇文章中,我会讲述为什么我会有这样的想法,在此之前,有几点我想要先声明一下:本文无意对编程语言进行评比,我要讲述的主体是为什么你应该学习 Scala。51CTO 之前曾发布过一篇 Java 程序员为何要学习 Scala 的文章,可能也会对你有所帮
3、助。目前 Scala 有两个实现方式,一种是在 JVM(Java 虚拟机)上运行,另一种是在 CLR(Common Language Runtime 的缩写,即公共语言运行库)上运行。不过,JVM 的实现方式更为成熟。如果你想要使用 .Net framework 框架,我认为最好还是听从 Lift framework 框架创始人大卫 波拉克(David Pollack)的建议:使用 F#。但在这篇文章中,我将只关注 JVM 这种实现方式。我是一个 Ruby 程序员,并且我会继续喜欢 Ruby,因为它是我见到过的最棒的动态语言。但我也喜欢 Scala,因为在其他工作领域,它提供的某些功能非常强大
4、。现在,让我们来仔细分析一下,是哪些原因让我选择 Scala 作为我的下一个编程语言:强大的编程语言Scala 是一门非常强大的语言,它允许用户使用命令和函数范式进行编写代码,因此,编程时你可以使用常用的命令式语句,就像我们使用 C、Java、PHP 以及很多其他语言一样,而且,你也可以使用类似 Lisp 语言中函数式语句,还有,你可以混合使用这两种风格的语句,就像 Ruby 或 Groovy。不过,当我们谈论的函数范式时,与 Ruby 和 Groovy 有一点不同的地方,那就是 Scala 几乎支持函数语言中所有已知的功能,比如,模式匹配(Pattern matching) 、延迟初始化(L
5、azy initialization) 、偏函数( Partial Function) 、不变性(Immutability) ,等等.即是说,认识到这样一个事实是非常重要的:Scala 的强大源自它对函数范式的支持,而后者令 Scala 成为一种高等级(high-level)的编程语言。对于高等级的编程语言,你只需关注 what(做什么)而不是如何做(how ) 。下面,让我们看一个 Java 示例:int x = 1,2,3,4,5,6; ArrayList res = new ArrayList(); for (int v : x) if (v % 2 = 1) res.add(new I
6、nteger(v); 仔细看一下上面这段示例代码,你会注意到,我想要做的“what”部分(过滤掉奇数值)仅出现在第四行中,而其余行则是“how”如何做的部分(结果变量的初始化以及一个循环操作) 。如果我想要再写一个过滤器,用于筛选偶数值,那就需要再写五行代码,而使用一门像 Scala 这样的高等级语言,你只需编写“what ”那部分的代码:val x = Array(1,2,3,4,5,6) val res = x filter ( _ % 2 = 1 ) /过滤奇数值 val res2 = x filter ( _ % 2 = 0 ) /过滤偶数值 我们可以看到,相对于上文中的 Java 代
7、码段,这段代码更加简洁,而且具有更好的可读性。高效Scala 是一种高效的编程语言,实际上,根据最新的 benchmark 性能测试,它几乎和 Java 一样快捷。在 JVM 上实现的 Scala 代码,可以编译为字节码,在这一过程中,代码通过优化阶段进行编译。尾递归优化是一个很好的示例,它可帮助用户专注于函数范式而无需以牺牲性能为代价。还有一个示例是,将 Scala 值类型对象转换为 Java 基本类型时进行的优化。可扩展Scala 语言本身的名字 Scala 来自 Scalable(可扩展的)一词,这意味着这种语言可以按照用户的需求进行扩展。因此,从根本上来讲,用户可以添加新的类型和控制结
8、构。比如,我想要添加一个简单的“loop ”控制结构:/ 一个简单的构建 def loop(range: Range)(op: Int= Unit) range foreach (op) loop(1 to 5)println / 1 2 3 4 5 loop(1 to 5)x = if (x % 2 = 0) println(x) / 2 4 还有几个更为复杂的例子,Actor lib,它是作为扩展被添加到 Scala 这一语言中的,我们将在下文中对它展开讨论。不过,Scala 之所以是可扩展的,在于互相关联的两点:它是真正的面向对象的语言和真正的函数式语言。面向对象Scala 中每个事物都
9、是对象(对象的方法除外) ,因此,没有必要对基本(primitive )类型或引用类型进行区分,这就是所谓的:统一对象模型(Uniform Object Model) 。但是,正如我之前在优化流程中所提到的,值类型对象被转换为 Java 基本类型,因此不必担心性能的问题。其内部还包含为类方法分组的单件对象(Singleton object) 。所有操作都是方法调用,+ - * ! / 都是方法,因此,没有必要进行操作符重载。非常精细的访问控制,用户可以控制对某些包的某些方法的访问。Scala 具有 trait,与 Ruby 中的 mixin 类似,就像 Java 中的 interfaces,但
10、实现了某些它们的方法,因此,用户在箱体(box)之外拥有富封装器(wrapper)和富交互接口(interface) 。函数式语言函数式语言具有很多特点,不过在扩展性这一语境中,我们所关心的是两个事实:函数是第一等级(first-class)的值这表示用户可以将函数作为值传递,也可以作为值返回。这样可以获得简洁而具有可读性的代码,正如上文中作为示例的过滤代码段。纯函数(pure function )Scala 支持没有副作用的纯函数,这意味着:如果你的输入相同,那么输出结果也总是相同。这样能够让代码更为安全,对代码测试也更为方便。但是,Scala 是通过什么方式来支持纯函数的呢?通过不变性(i
11、mmutability):偏向固定的引用(与 java 中的 final 或其他语言中的 constant 类似)以及具有不变的数据结构,一旦创建便不可修改。不变性是拥有纯函数的安全保证,但并不是唯一的方式。没有不变性,你仍然可以编写安全的代码。这就是为什么 Scala 不是强制推行不变性而只是鼓励使用它。最终,你会发现 Scala 中许多数据结构具有了两种实现方式,一种是可变的,另一种是不可变的,不可变的数据结构是缺省导入的。每当提到不变性时,有人就会开始担心性能的问题,对于某些情况,这种担忧并非毫无来由,但对于 Scala,最终结果却与这一担忧相反。不可变的数据结构相对于可变的数据结构,更
12、有助于获得较高的效率。其原因之一在于强大的垃圾收集器(garbage collector) ,与 JVM 中的垃圾收集器类似。更佳的并行模型当涉及到线程这一问题时,Scala 支持传统的 shared data 模型。但是,使用这种模型较长一段时间之后,许多人发现使用这种模型编写代码,非常难以实现以及进行测试。你总是需要考虑死锁问题和竞争条件。因此,Scala 提供了另一个称为 Actor 的并行模型,其中,actor 通过它的收件箱来发送和接收非同步信息,而不是共享数据。这种方式被称为:shared nothing 模型。一旦你不再顾虑共享数据的问题,也就不必再为代码同步和死锁问题而头痛。被
13、发送信息的不变性本质以及 actor 中串行处理,这两者使得对于并行的支持更为简便。有关 Scala 并行的问题,请参阅这篇文章,对于这个概念你会有更好的理解。在讲述下一个要点之前,我需要提到这样一个事实,一些人将 Actor 的使用视为编程语言的一种进化。正如,Java 的出现,将程序员们从指针和内存管理的泥淖中拯救出来一样,Scala 的到来,让程序员们不必再为代码同步以及共享数据模型整天苦思冥想。静态类型当我想要讲述这一要点的时候,才发现,对于静态类型语言的正反两面,我试图给予同样的关注。事实上,关于这一话题的争论总是没完没了,但我要作出两点总结,而这两点是大多数人讨论的热点:使用静态类
14、型语言编写的代码更加健壮(robust)TDD 的存在,让许多关于动态类型语言和健壮代码的讨论失去了意义,虽然这是正确的,当我们仍然不能忽视这样一个事实:对于动态类型语言,你需要编写更多的测试代码来检查类型,而在静态类型语言中,你可以将这些问题交给编译器处理。此外,还有一些人认为,使用静态类型语言,你的代码将具有更好的自我记录。使用静态类型语言编写的代码过于严格和冗长像我这样的动态类型语言的粉丝,认为通过鸭子类型(duck typing)可以写出更具动态性的代码结构。但同时他们还会抱怨,静态类型语言导致代码冗长。关于静态类型与动态类型的争论,在 51CTO 之前发布的这篇文章中可以看到更多信息
15、。作为静态类型语言,Scala 具有第一条中提到的优点,但是,第二点呢?Scala 具有一个灵活的类型系统,并且可能是这一类型中最好的。很多情况下,如果你没有指定类型,这一系统将能够对类型进行推断。例如,你可以这样编写代码:val list: ListString = List(“one“, “two“, “three“) /list: ListString = List(one, two, three) val s: String = “Hello World!“ /s: java.lang.String = hello world! 但你也可以这样编写代码:val list = List(
16、“one“, “two“, “three“) /list: ListString = List(one, two, three) val s = “Hello World!“ /s: java.lang.String = hello world! 非常好,无论如何,它解决了代码冗长的问题。但像鸭子类型(duck typing)那样的问题,会怎样呢?答案还是:Scala 的类型系统具有的某些灵活性,可以让你编写如下的代码:def eatT println(last + “, “ + zip) case _ = println(“not an address“) / 缺省情况 对于第一种情况,模式
17、 Name(first, last) 嵌套在模式 Address() 中。 其中的 last 值,被传递到 Name 构造函数,然后进行提取,因此在箭头右侧的表达式中是可用的。那么,模式匹配的意义为什么你需要模式匹配?我们都会有复杂的数据。如果我们坚持严格的面向对象编程,那么我们就不愿去关注数据树的内部情况。相反,我们想要调用方法,让方法来做这些事情。如果我们有能力完成这件事,就不会非常需要模式匹配,因为方法满足了我们的要求。但是,很多时候对象没有我们所需的方法,并且我们不能(或不愿)为对象添加新的方法。因此,模式匹配被认为是一种获得扩张性的有效方法,并且,它还为该问题提供了一种不错的解决方案
18、,访问者设计模式所导致的冗长除外。不管怎样,强烈推荐你看看上面所提到的文章中”扩展性的两个方向“(Two directions of extensibility)那个小节。简单的 DSL(特定领域语言)编写 DSL,Scala 是一个很好的选择。事实上,Scala 适用于内部和外部 DSL。在这篇文章中,你可以找到一些使用 Ruby 和 Scala 编写内部 DSL 的特点比较。下面这篇文章也很棒,是关于使用 Scala 编写内部 DSL 的:Boolean Algebra Internal DSL in Scala (aka fun with Unicode names )。此外,对于外部
19、DSL,Scala 也应该是首选语言,背后的原因是解析器组合子库(parser combinator lib) ,它让为新语言编写编译器成为一件很酷的事。与 Java 代码之间的互操作性在 JVM 上的实现 Scala 的程序可以无缝地与 Java 平台整合,很多 Scala 类型实际上都编译为 Java 类型,因此,用户可以放心地使用 Java 类型。而且,你也可以混合地使用 JVM 语言来编程,如:JRuby、Groovy、Clojure 等。这里有一篇不错的文章,提供了这种示例。学习型语言我有两个习惯,在 Scala 的学习过程中,我坚持了这两个习惯:遇到新的技术术语,访问维基百科,理解
20、更多信息;比如 Function literal(文本函数) 、Referentially transparent(引用透明度) 、Partial function(偏函数) 、Currying(科里华) ,还有很多其他术语。参考我对其他语言的理解,检查这些术语的涵义是否实现。通过一些好的练习,如编写没有副作用的纯函数,将精力集中在代码中的“what”部分,而将“how”的部分交给语言处理;这两个习惯让我获得更多知识,也提高了代码的质量。团队Scala 由马丁奥德斯基(Martin Odersky)设计,他是瑞士联邦理工学院洛桑分校(EPFL)编程方法实验室小组的管理者。奥德斯基曾受雇于 Su
21、n 公司编写 Java 1.1 编译器,他还是 Java 1.1 到 Java 1.4 的 Javac 主要开发者。此外,他还是 Java Generics 的提出者。51CTO 编辑曾通过电子邮件与奥德斯基就 Scala 的语言特性进行了交流,并得到了回复信件如下。Scala 现在由奥德斯基和他在瑞士联邦理工学院洛桑分校的团队维护。不过,还有其他一些具有才华的开发者参与,通过多年的工作,他们共同打造出了 Scala 这一编程语言。来源Scala 受到了多种语言的启发:大多数的句法来自 Java 和 C#。其他一些元素也来自 Java,比如:基本类型(basic type) 、类库,以及其运行
22、模型。它所用的统一对象模型是由 Smalltalk 最先使用的。通用嵌套(universal nesting)的理念也出现在 Algol、Simula 中,而且最近还出现在 Beta 和 gbeta 中。函数式编码的方法在精神上也与 ML 语言家族类似,该语言家族中包含 SML、OCaml ,以及最主要的成员 F#。Scala 标准库中的许多较高阶的函数,也出现在 ML 和 Haskell 中。Scala 的隐式参数也是受到 Haskell 类型类的启发。Scala 基于 actor 的并行库主要是受到 Erlang 的启发。将插入(infix)操作符视为函数,以及允许文本函数(或 block
23、 区块)作为参数,以使库能够定义控制结构,这些特定的理念可以回溯至 Iswim 和 Smalltalk。专家观点实际上,像詹姆士斯特拉坎(James Strachan:编程语言 Groovy 的创始人)的这样的言语让人感到有点惊喜:说实话,如果有人在 2003 年给我一本由马丁奥德斯基 (Martin Odersky)、莱克斯斯彭(Lex Spoon)和比尔文纳斯(Bill Venners)合著的Programming in Scala ,我很可能不会再去创建 Groovy。在结束之前,我做一下总结:我喜欢 Scala,因为它是高效的、学习型的语言,具有较好的并行模型,以及非常适用于编写 DSL。原文:Scala is my next choice作者:khelll 译者:司马牵牛【相关阅读】Scala 取代 Java?可能吗?热议仍持续不断 Groovy 创始人: Java 面临终结 Scala 将取而代之 Scala 如何改变了我的编程风格:从命令式到函数式 Scala 的类型系统 比 Java 更灵活 Java 程序员,你为什么要关注 Scala 【责任编辑:杨赛 TEL:(010