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

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。
分享到:
评论

相关推荐

    原生js图片圆形排列按钮控制3D旋转切换插件.zip

    原生js图片圆形排列按钮控制3D旋转切换插件.zip

    类似c++数组的python包

    内含二维数组与三维数组,分别为list2nd,list3rd

    原生js颜色随机生成9x9乘法表代码.zip

    原生js颜色随机生成9x9乘法表代码.zip

    原生js实现图片叠加滚动切换代码.zip

    原生js实现图片叠加滚动切换代码.zip

    【Academic tailor】学术小裁缝必备知识点:全局注意力机制(GAM)TensorFlow

    【Academic tailor】学术小裁缝必备知识点:全局注意力机制(GAM) 注意力机制是深度学习中的重要技术,尤其在序列到序列(sequence-to-sequence)任务中广泛应用,例如机器翻译、文本摘要和问答系统等。这一机制由 Bahdanau 等人在其论文《Neural Machine Translation by Jointly Learning to Align and Translate》中首次提出。以下将详细介绍这一机制的背景、核心原理及相关公式。 全局注意力机制(Global Attention Mechanism, GAM)由 《Global Attention Mechanism: Retain Information to Enhance Channel-Spatial Interactions》提出,是一篇针对计算机视觉任务提出的方法。这篇文章聚焦于增强深度神经网络中通道和空间维度之间的交互,以提高分类任务的性能。与最早由 Bahdanau 等人提出的用于序列到序列任务的注意力机制 不同,这篇文章的重点是针对图像分类任务,并未专注于序

    基于SpringBoot的“篮球论坛系统”的设计与实现(源码+数据库+文档+PPT).zip

    本项目在开发和设计过程中涉及到原理和技术有: B/S、java技术和MySQL数据库等;此文将按以下章节进行开发设计; 第一章绪论;剖析项目背景,说明研究的内容。 第二章开发技术;系统主要使用了java技术, b/s模式和myspl数据库,并对此做了介绍。 第三章系统分析;包罗了系统总体结构、对系统的性能、功能、流程图进行了分析。 第四章系统设计;对软件功能模块和数据库进行详细设计。 第五章系统总体设计;对系统管理员和用户的功能进行描述, 第六章对系统进行测试, 第七章总结心得;在论文最后结束章节总结了开发这个系统和撰写论文时候自己的总结、感想,包括致谢。

    毕业设计&课设_iOS 商城项目,含购物与商家管理功能,用 Sqlite,有账号示例,适合 iOS 开发练习.zip

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

    镗夹具总工艺图.dwg

    镗夹具总工艺图

    原生js树叶数字时钟代码.rar

    原生js树叶数字时钟代码.rar

    近代非线性回归分析-韦博成1989

    近代非线性回归分析-韦博成1989

    Rust语言中冒泡排序算法的高效实现与优化

    内容概要:本文详细介绍了用 Rust 语言实现冒泡排序算法的具体步骤,以及通过设置标志位来优化算法性能的方法。示例代码包括了函数定义、内外层循环逻辑、标志位的应用,并在主函数中展示了如何调用 bubble_sort 函数并显示排序前后的数组。 适合人群:具有基本 Rust 编程基础的学习者和开发者。 使用场景及目标:适用于想要深入了解 Rust 中冒泡排序实现方式及其优化技巧的技术人员。通过本篇文章,能够掌握 Rust 基本语法以及算法优化的基本思想。 阅读建议:除了仔细阅读和理解每一部分的内容外,还可以尝试修改代码,改变数据集大小,进一步探索冒泡排序的时间复杂度和优化效果。此外,在实际应用时也可以考虑引入并发或其他高级特性以提升性能。

    培训课件 -安全隐患分类与排查治理.pptx

    培训课件 -安全隐患分类与排查治理.pptx

    1-中国各地级市的海拔标准差-社科数据.zip

    中国各地级市的海拔标准差数据集提供了298个地级市的海拔变异性信息。海拔标准差是衡量某地区海拔高度分布离散程度的统计指标,它通过计算各测量点海拔与平均海拔之间的差异来得出。这一数据对于评估地形起伏对网络基础设施建设的影响尤为重要,因为地形的起伏度不仅会增加建设成本,还会影响信号质量。此外,由于地形起伏度是自然地理变量,它与经济社会因素关联性较小,因此被用作“宽带中国”试点政策的工具变量,以研究网络基础设施建设对经济的影响。数据集中包含了行政区划代码、地区、所属省份、所属地域、长江经济带、经度、纬度以及海拔标准差等关键指标。这些数据来源于地理空间数据云,并以Excel和dta格式提供,方便研究者进行进一步的分析和研究。

    YOLO算法的原理与实现.pdf

    YOLO算法的原理与实现

    机器学习用于视网膜病变预测:使用 XGBoost 揭示年龄和HbA1c 的重要性 -论文

    视网膜病变是糖尿病和高血压的主要微血管并发症。如果不及时治疗,可能会导致失明。据估计,印度三分之一的成年人患有糖尿病或高血压,他们未来患视网膜病变的风险很高。我们研究的目的是检查糖化血红蛋白 (HbA1c)、血压 (BP) 读数和脂质水平与视网膜病变的相关性。我们的主要假设是,血糖控制不佳(表现为高 HbA1c 水平、高血压和异常脂质水平)会导致视网膜病变风险增加。我们使用眼底照相机筛查了 119 名印度患者的视网膜病变,并获取了他们最近的血压、HbA1c 和血脂谱值。然后,我们应用 XGBoost 机器学习算法根据他们的实验室值预测是否存在视网膜病变。我们能够根据这些关键生物标志物高精度地预测视网膜病变。此外,使用 Shapely Additive Explanations (SHAP),我们确定了对模型最重要的两个特征,即年龄和 HbA1c。这表明血糖控制不佳的老年患者更有可能出现视网膜病变。因此,这些高风险人群可以成为早期筛查和干预计划的目标,以防止视网膜病变发展为失明。

    RL Base强化学习:信赖域策略优化(TRPO)算法TensorFlow实现

    在强化学习(RL)领域,如何稳定地优化策略是一个核心挑战。2015 年,由 John Schulman 等人提出的信赖域策略优化(Trust Region Policy Optimization, TRPO)算法为这一问题提供了优雅的解决方案。TRPO 通过限制策略更新的幅度,避免了策略更新过大导致的不稳定问题,是强化学习中经典的策略优化方法之一。

    Spring 应用编译为原生可执行文件.zip

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

    1-中国各地区普通小学毕业生数(1999-2020年)-社科数据.zip

    这组数据涵盖了1999至2020年间中国各地区普通小学毕业生的数量。它为我们提供了一个深入了解中国教育领域中普通小学阶段教育水平和教育资源分配情况的窗口。通过分析这些数据,可以为制定科学合理的教育政策提供依据,同时,通过比较不同城市的普通小学毕业生数,也能为城市规划和劳动力市场调查提供参考。数据来源于中国区域统计年鉴和中国各省市统计年鉴,包含了8472个样本,以面板数据的形式呈现。这些数据对于掌握中国教育态势具有重要的参考价值。

    原生js制作拖拽排列排序代码.zip

    原生js制作拖拽排列排序代码.zip

    PixPin截图工具,非常好用的一款截图工具

    PixPin截图工具,非常好用的一款截图工具

Global site tag (gtag.js) - Google Analytics