`
pure
  • 浏览: 354386 次
社区版块
存档分类
最新评论

Ruby高手点评Scala编程语言十大绝招

阅读更多
原文地址:http://developer.51cto.com/art/200907/138074.htm

几个月前,我开始使用 Scala。我用过的编程语言还有 Pascal、C、C++、Java、PHP、Ruby 和 Groovy,但是,与所有那些我用过的语言相比,我发觉 Scala 是一门与众不同的语言。我是在看到 Twitter 上关于 Ruby 和 Scala 讨论之后,才开始我的 Scala 编程之旅的。现在,使用 Scala 编程已经几个月了,关于 Scala 我有两点想法,虽然类似的想法已广为人知,但我仍很想与你们分享:

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

◆Scala 的确很棒。

◆我的确认为计算机学院应该开一门 Scala 的语言课程。

在这篇文章中,我会讲述为什么我会有这样的想法,在此之前,有几点我想要先声明一下:

本文无意对编程语言进行评比,我要讲述的主体是为什么你应该学习 Scala。51CTO之前曾发布过一篇 Java 程序员为何要学习Scala的文章,可能也会对你有所帮助。

目前 Scala 有两个实现方式,一种是在 JVM(Java 虚拟机)上运行,另一种是在 CLR(Common Language Runtime 的缩写,即公共语言运行库)上运行。不过,JVM 的实现方式更为成熟。如果你想要使用 .Net framework 框架,我认为最好还是听从 Lift framework 框架创始人大卫·波拉克(David Pollack)的建议:使用 F#。但在这篇文章中,我将只关注 JVM 这种实现方式。

我是一个 Ruby 程序员,并且我会继续喜欢 Ruby,因为它是我见到过的最棒的动态语言。但我也喜欢 Scala,因为在其他工作领域,它提供的某些功能非常强大。

现在,让我们来仔细分析一下,是哪些原因让我选择 Scala 作为我的下一个编程语言:

强大的编程语言

Scala 是一门非常强大的语言,它允许用户使用命令和函数范式进行编写代码,因此,编程时你可以使用常用的命令式语句,就像我们使用 C、Java、PHP 以及很多其他语言一样,而且,你也可以使用类似 Lisp 语言中函数式语句,还有,你可以混合使用这两种风格的语句,就像 Ruby 或 Groovy。

不过,当我们谈论的函数范式时,与 Ruby 和 Groovy 有一点不同的地方,那就是 Scala 几乎支持函数语言中所有已知的功能,比如,模式匹配(Pattern matching)、延迟初始化(Lazy 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 Integer(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 代码段,这段代码更加简洁,而且具有更好的可读性。

高效

Scala 是一种高效的编程语言,实际上,根据最新的 benchmark 性能测试,它几乎和 Java 一样快捷。在 JVM 上实现的 Scala 代码,可以编译为字节码,在这一过程中,代码通过优化阶段进行编译。尾递归优化是一个很好的示例,它可帮助用户专注于函数范式而无需以牺牲性能为代价。还有一个示例是,将 Scala 值类型对象转换为 Java 基本类型时进行的优化。

可扩展

Scala 语言本身的名字 Scala 来自 Scalable(可扩展的)一词,这意味着这种语言可以按照用户的需求进行扩展。因此,从根本上来讲,用户可以添加新的类型和控制结构。比如,我想要添加一个简单的“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 中每个事物都是对象(对象的方法除外),因此,没有必要对基本(primitive)类型或引用类型进行区分,这就是所谓的:统一对象模型(Uniform Object Model)。但是,正如我之前在优化流程中所提到的,值类型对象被转换为 Java 基本类型,因此不必担心性能的问题。其内部还包含为类方法分组的单件对象(Singleton object)。

◆所有操作都是方法调用,+ - * ! / 都是方法,因此,没有必要进行操作符重载。

◆非常精细的访问控制,用户可以控制对某些包的某些方法的访问。

◆Scala 具有  trait,与 Ruby 中的 mixin 类似,就像 Java 中的 interfaces,但实现了某些它们的方法,因此,用户在箱体(box)之外拥有富封装器(wrapper)和富交互接口(interface)。

函数式语言

函数式语言具有很多特点,不过在扩展性这一语境中,我们所关心的是两个事实:

◆函数是第一等级(first-class)的值

这表示用户可以将函数作为值传递,也可以作为值返回。这样可以获得简洁而具有可读性的代码,正如上文中作为示例的过滤代码段。

◆纯函数(pure function)

Scala 支持没有副作用的纯函数,这意味着:如果你的输入相同,那么输出结果也总是相同。这样能够让代码更为安全,对代码测试也更为方便。

但是,Scala 是通过什么方式来支持纯函数的呢?通过不变性(immutability):偏向固定的引用(与 java 中的 final 或其他语言中的 constant 类似)以及具有不变的数据结构,一旦创建便不可修改。

不变性是拥有纯函数的安全保证,但并不是唯一的方式。没有不变性,你仍然可以编写安全的代码。这就是为什么 Scala 不是强制推行不变性而只是鼓励使用它。最终,你会发现 Scala 中许多数据结构具有了两种实现方式,一种是可变的,另一种是不可变的,不可变的数据结构是缺省导入的。

每当提到不变性时,有人就会开始担心性能的问题,对于某些情况,这种担忧并非毫无来由,但对于 Scala,最终结果却与这一担忧相反。不可变的数据结构相对于可变的数据结构,更有助于获得较高的效率。其原因之一在于强大的垃圾收集器(garbage collector),与 JVM 中的垃圾收集器类似。

更佳的并行模型

当涉及到线程这一问题时,Scala 支持传统的 shared data 模型。但是,使用这种模型较长一段时间之后,许多人发现使用这种模型编写代码,非常难以实现以及进行测试。你总是需要考虑死锁问题和竞争条件。因此,Scala 提供了另一个称为 Actor 的并行模型,其中,actor 通过它的收件箱来发送和接收非同步信息,而不是共享数据。这种方式被称为:shared nothing 模型。一旦你不再顾虑共享数据的问题,也就不必再为代码同步和死锁问题而头痛。

被发送信息的不变性本质以及 actor 中串行处理,这两者使得对于并行的支持更为简便。

有关 Scala 并行的问题,请参阅这篇文章,对于这个概念你会有更好的理解。

在讲述下一个要点之前,我需要提到这样一个事实,一些人将 Actor 的使用视为编程语言的一种进化。正如,Java 的出现,将程序员们从指针和内存管理的泥淖中拯救出来一样,Scala 的到来,让程序员们不必再为代码同步以及共享数据模型整天苦思冥想。

静态类型

当我想要讲述这一要点的时候,才发现,对于静态类型语言的正反两面,我试图给予同样的关注。事实上,关于这一话题的争论总是没完没了,但我要作出两点总结,而这两点是大多数人讨论的热点:

◆使用静态类型语言编写的代码更加健壮(robust)

TDD 的存在,让许多关于动态类型语言和健壮代码的讨论失去了意义,虽然这是正确的,当我们仍然不能忽视这样一个事实:对于动态类型语言,你需要编写更多的测试代码来检查类型,而在静态类型语言中,你可以将这些问题交给编译器处理。此外,还有一些人认为,使用静态类型语言,你的代码将具有更好的自我记录。

◆使用静态类型语言编写的代码过于严格和冗长

像我这样的动态类型语言的粉丝,认为通过鸭子类型(duck typing)可以写出更具动态性的代码结构。但同时他们还会抱怨,静态类型语言导致代码冗长。

关于静态类型与动态类型的争论,在51CTO之前发布的这篇文章中可以看到更多信息。

作为静态类型语言,Scala 具有第一条中提到的优点,但是,第二点呢?

Scala 具有一个灵活的类型系统,并且可能是这一类型中最好的。很多情况下,如果你没有指定类型,这一系统将能够对类型进行推断。

例如,你可以这样编写代码:
    val list: List[String] = List("one", "two", "three")   
    //list: List[String] = List(one, two, three)     
    val s: String = "Hello World!"   
    //s: java.lang.String = hello world! 


但你也可以这样编写代码:

   val list = List("one", "two", "three")   
   //list: List[String] = List(one, two, three)     
   val s = "Hello World!"   
   //s: java.lang.String = hello world! 


非常好,无论如何,它解决了代码冗长的问题。但像鸭子类型(duck typing)那样的问题,会怎样呢?

答案还是:Scala 的类型系统具有的某些灵活性,可以让你编写如下的代码:
 def eat[T <: Animal](a: T) // whatever 


其中,我们将类型 T 定义为 Animal 的子类型。还可以更加灵活:
  def eat[T <: {def eat(): Unit}](a: T) // whatever 


其中,我们将类型 T 定义为一个具有非法  eat 的类型。

事实上,Scala 的类型系统非常丰富,你可以在这里找到更多信息。

模式匹配

我必须坦白,在犹豫良久之后,我才决定写一写 Scala 的这一特点。事实上,我本来没有打算讨论 Scala 的函数功能,但看到一篇有关对象分支(switch)应用的文章后,我想,还是有必要聊聊这个特点。以下内容基本上都来自这篇博客文章:

模式匹配究竟是用来做什么的?它让你可以将一个值对多种情况(case)进行匹配,有点类似 Java 中的分支(switch)语句。但它不是仅仅匹配数字(这是分支语句的作用),而是用户能够对本质上为对象创建形式(creation form)的事物进行匹配。

以下示例也来自上文提到的博客:

   x match {   
   case Address(Name(first, last), street, city, state, zip) => println(last + ", " + zip)   
   case _ => println("not an address") // 缺省情况   
   } 


对于第一种情况,模式 Name(first, last) 嵌套在模式 Address(…) 中。 其中的 last 值,被传递到 Name 构造函数,然后进行提取,因此在箭头右侧的表达式中是可用的。

那么,

模式匹配的意义

为什么你需要模式匹配?我们都会有复杂的数据。如果我们坚持严格的面向对象编程,那么我们就不愿去关注数据树的内部情况。相反,我们想要调用方法,让方法来做这些事情。如果我们有能力完成这件事,就不会非常需要模式匹配,因为方法满足了我们的要求。但是,很多时候对象没有我们所需的方法,并且我们不能(或不愿)为对象添加新的方法。

因此,模式匹配被认为是一种获得扩张性的有效方法,并且,它还为该问题提供了一种不错的解决方案,访问者设计模式所导致的冗长除外。

不管怎样,强烈推荐你看看上面所提到的文章中”扩展性的两个方向“(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 )。

此外,对于外部 DSL,Scala 也应该是首选语言,背后的原因是解析器组合子库(parser combinator lib),它让为新语言编写编译器成为一件很酷的事。

与 Java 代码之间的互操作性

在 JVM 上的实现 Scala 的程序可以无缝地与 Java 平台整合,很多 Scala 类型实际上都编译为 Java 类型,因此,用户可以放心地使用 Java 类型。而且,你也可以混合地使用 JVM 语言来编程,如:JRuby、Groovy、Clojure 等。这里有一篇不错的文章,提供了这种示例。

学习型语言

我有两个习惯,在 Scala 的学习过程中,我坚持了这两个习惯:

◆遇到新的技术术语,访问维基百科,理解更多信息;比如 Function literal(文本函数)、Referentially transparent(引用透明度)、Partial function(偏函数)、Currying(科里华),还有很多其他术语。

◆参考我对其他语言的理解,检查这些术语的涵义是否实现。

通过一些好的练习,如编写没有副作用的纯函数,将精力集中在代码中的“what”部分,而将“how”的部分交给语言处理;这两个习惯让我获得更多知识,也提高了代码的质量。

团队

Scala 由马丁·奥德斯基(Martin Odersky)设计,他是瑞士联邦理工学院洛桑分校(EPFL)编程方法实验室小组的管理者。奥德斯基曾受雇于 Sun 公司编写 Java 1.1 编译器,他还是 Java 1.1 到 Java 1.4 的 Javac 主要开发者。此外,他还是 Java Generics 的提出者。51CTO编辑曾通过电子邮件与奥德斯基就 Scala 的语言特性进行了交流,并得到了回复信件如下。

Scala 现在由奥德斯基和他在瑞士联邦理工学院洛桑分校的团队维护。不过,还有其他一些具有才华的开发者参与,通过多年的工作,他们共同打造出了 Scala 这一编程语言。

来源

Scala 受到了多种语言的启发:

◆大多数的句法来自 Java 和 C#。

◆其他一些元素也来自 Java,比如:基本类型(basic type)、类库,以及其运行模型。

◆它所用的统一对象模型是由 Smalltalk 最先使用的。

◆通用嵌套(universal nesting)的理念也出现在 Algol、Simula 中,而且最近还出现在 Beta 和 gbeta 中。

◆函数式编码的方法在精神上也与 ML 语言家族类似,该语言家族中包含 SML、OCaml,以及最主要的成员 F#。

◆Scala 标准库中的许多较高阶的函数,也出现在 ML 和 Haskell 中。

◆Scala 的隐式参数也是受到 Haskell 类型类的启发。Scala 基于 actor 的并行库主要是受到 Erlang 的启发。

◆将插入(infix)操作符视为函数,以及允许文本函数(或 block 区块)作为参数,以使库能够定义控制结构,这些特定的理念可以回溯至 Iswim 和Smalltalk。

专家观点

实际上,像詹姆士·斯特拉坎(James Strachan:编程语言 Groovy 的创始人)的这样的言语让人感到有点惊喜:

说实话,如果有人在 2003 年给我一本由马丁·奥德斯基(Martin Odersky)、莱克斯·斯彭(Lex Spoon)和比尔·文纳斯(Bill Venners)合著的《Programming in Scala》,我很可能不会再去创建 Groovy。

在结束之前,我做一下总结:

我喜欢 Scala,因为它是高效的、学习型的语言,具有较好的并行模型,以及非常适用于编写 DSL。
分享到:
评论

相关推荐

    PPT模板 -龙湖新员工转正答辩模板.pptx

    PPT模板 -龙湖新员工转正答辩模板.pptx

    PPT模板 -生产计划管理.pptx

    PPT模板 -生产计划管理.pptx

    生产单元数字化改造23年国赛

    生产单元数字化改造23年国赛

    ECharts柱状图-极坐标系下的堆叠柱状图2.rar

    图表效果及代码实现讲解链接:https://blog.csdn.net/zhangjiujiu/article/details/143997013

    机器人算法的 Python 示例代码 .zip

    Pythonbot高斯网格图射线投射网格图激光雷达至网格地图k-均值对象聚类矩形接头大满贯迭代最近点 (ICP) 匹配FastSLAM 1.0路径规划动态窗口方法基于网格的搜索Dijkstra 算法A* 算法D*算法D* Lite 算法位场算法基于网格的覆盖路径规划国家网格规划偏极采样车道采样概率路线图(PRM)规划快速探索随机树(RRT)回程时间*RRT* 和 reeds-shepp 路径LQR-RRT*五次多项式规划Reeds Shepp 规划基于LQR的路径规划Frenet 框架中的最佳轨迹路径追踪移动到姿势控制斯坦利控制后轮反馈控制线性二次调节器 (LQR) 速度和转向控制模型预测速度和转向控制采用 C-GMRES 的非线性模型预测控制手臂导航N关节臂对点控制带避障功能的手臂导航航空导航无人机三维轨迹跟踪火箭动力着陆双足动物倒立摆双

    sql综合学习基础知识及练习题考试题实测题.zip

    SQL,全称为结构化查询语言(Structured Query Language),是用于管理和操作关系型数据库的标准化语言。它广泛应用于数据插入、查询、更新和删除等操作,并且拥有超过40年的历史,证明了其在数据处理领域的核心地位。以下是对SQL综合学习基础知识及练习题考试题实测题的介绍

    java面向对象 - 类与对象.doc

    java面向对象 - 类与对象 在Java编程语言中,面向对象编程(OOP)是一个核心概念。它强调以对象作为程序的基本单位,并将相关的数据和功能封装在对象中。类和对象是Java OOP的两个关键组成部分。 ### 类(Class) 类是一个模板或蓝图,它定义了对象的属性和行为。我们可以将类视为对象的类型或种类。通过类,我们可以创建(实例化)具有特定属性和行为的对象。 类的组成部分通常包括: 1. **成员变量**(属性):用于存储对象的状态或数据。 2. **方法**(行为):定义了对象可以执行的操作或功能。 3. **构造方法**:一种特殊类型的方法,用于在创建对象时初始化其状态。 4. **块**(如静态块、实例初始化块):用于执行类级别的初始化代码。 5. **嵌套类**:一个类可以包含其他类,这被称为嵌套或内部类。 ### 对象(Object) 对象是类的实例。它是根据类模板创建的具体实体,具有自己的状态和行为。每个对象都是其类的一个唯一实例,可以访问其类中定义的属性和方法。 创建对象的过程通常涉及以下几个步骤: 1. **声明**:指定对象的类型(即其所属的类

    原生JS实现鼠标感应图片左右滚动代码.zip

    原生JS实现鼠标感应图片左右滚动代码.zip

    随机密码生成器,支持字符、数字、字母大小写组合

    随机密码生成器,支持字符、数字、字母大小写组合

    自动化部署管道创建的代码库(含 Concourse 和 Jenkins 相关).zip

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。

    高等工程数学试题详解:矩阵分析与最优化方法

    内容概要:本文档为一份高级数学复习试题,内容涵盖线性代数、数值分析及最优化理论等领域,主要包括矩阵范数的计算、遗传算法中的变异操作、内点法解非线性优化问题、证明矩阵有互异特征值、求解矩阵的标准形以及应用单纯形法和FR共轭梯度法解决具体的数学问题等方面。 适合人群:正在备考研究生入学考试或者准备参加各类数学竞赛的学生、对高等数学感兴趣的学习者及从事相关领域科研工作的专业人士。 使用场景及目标:用于巩固和检验个人关于矩阵论、优化方法及概率统计的知识掌握情况,帮助应试者系统地复习相关考点,提高解题技巧。 阅读建议:建议结合具体题目深入理解每一个概念及其应用方式,遇到复杂的计算或证明步骤不妨动手尝试推导一次,这样有助于加深记忆并培养灵活运用知识的能力。同时,在理解算法原理的基础上,还可以参考一些实际案例来进行练习。

    使用了脉冲码调制(PCM).计算了所需的比特率和信号量化误差Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    Google 表格 Python API.zip

    Google Spreadsheet Python API v4Google Sheets 配合使用的简单界面。特征通过标题、关键字或URL打开电子表格。读取、写入和格式化单元格区域。共享和访问控制。批量更新。安装pip install gspread要求Python 3.8+。基本用法在 Google API 控制台中创建凭据开始使用 gspreadimport gspreadgc = gspread.service_account()# Open a sheet from a spreadsheet in one gowks = gc.open("Where is the money Lebowski?").sheet1# Update a range of cells using the top left corner addresswks.update([[1, 2], [3, 4]], "A1")# Or update a single cellwks.update_acell("B42", "it's

    AICon 2024全球人工智能开发与应用大会(脱敏)PPT合集(30份).zip

    AICon 2024全球人工智能开发与应用大会(脱敏)PPT合集,共30份。 AI辅助编程测评与企业实践 SmartEV和AI 蔚来的思考与实践 下一代 RAG 引擎的技术挑战与实现 书生万象大模型的技术演进与应用探索 人工智能行业数据集构建及模型训练方法实践周华 全方位评测神经网络模型的基础能力 千亿参数 LLM 的训练效率优化 向量化与文档解析技术加速大模型RAG应用落地 基于大模型的缺陷静态检查 多环境下的 LLM Agent 应用与增强 大模型在华为推荐场景中的探索和应用 大模型在推荐系统中的落地实践 大模型的异构计算和加速 大模型辅助需求代码开发 大语言模型在法律领域的应用探索 大语言模型在计算机视觉领域的应用 大语言模型的幻觉检测 小米大模型端侧部署落地探索 快手可图大模型的技术演进与应用探索 提升大模型知识密度,做高效的终端智能 电商大模型及搜索应用实践 百度大模型 原生安全构建之路 硅基流动高性能低成本的大模型推理云实践 语言模型驱动的软件工具思考:可解释与可溯源 长文本大模型推理实践:以 KVCache 为中心的分离式推理架构 阿里云 AI 搜索 RAG 大模型优

    子弹打穿金属后留下弹痕flash动画.zip

    子弹打穿金属后留下弹痕flash动画.zip

    雷达目标一维距离像仿真实验,以及多目标成像 matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    原生js竖直动画手风琴下拉菜单代码.zip

    原生js竖直动画手风琴下拉菜单代码.zip

    受循环荷载作用的土壤或路面层分析Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    Centos6.x通过RPM包升级OpenSSH9.7最新版 升级有风险,前务必做好快照,以免升级后出现异常影响业务

    Centos6.x通过RPM包升级OpenSSH9.7最新版 升级有风险,前务必做好快照,以免升级后出现异常影响业务

    营销策划 -阿道夫洗护品牌新品小红书新品营销方案.pptx

    营销策划 -阿道夫洗护品牌新品小红书新品营销方案.pptx

Global site tag (gtag.js) - Google Analytics