Scala是什么?可伸展的语言!

开发 后端
本文介绍Scala是什么。从技术层面上来说,Scala是一种把面向对象和函数式编程理念加入到静态类型语言中的混血儿,它是面向对象和函数式编程的熔合,具有绝佳的可伸展性。

Scala是什么

Scala语言的名称来自于“可伸展的语言”。之所以这样命名,是因为他被设计成随着使用者的需求而成长。你可以把Scala应用在很大范围的编程任务上,从写个小脚本到建立个大系统。

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

Scala是很容易进入的语言。它跑在标准的Java平台上,可以与所有的Java库实现无缝交互。它也是用来编写脚本把Java控件链在一起的很好的语言。但是用它来建立大系统和可重用控件的架构将更能够发挥它的力量。

从技术层面上来说,Scala是一种把面向对象和函数式编程理念加入到静态类型语言中的混血儿。Scala的许多不同的方面都展现了面向对象和函数式编程的熔合;或许它比其他那些广泛使用的语言更有渗透性。在可伸展性方面,这两种编程风格具有互补的力量。Scala的函数式编程使得它便于快速地从简单的碎片开始建立一些有趣的东西。它的面向对象特性又使它便于构造大型系统并使它们适应于新的需求。Scala中这两种风格的组合使得它有可能表达新的编程模式和控件抽象。并产生了易读、简洁的编程风格。由于它良好的延展性,用Scala编程将会有很多的乐趣。

不同尺寸的程序倾向于需要不同的编程结构。举例来说,考虑以下的Scala程序:

  1. var capital = Map("US"->"Washington""France" -> "Paris")  
  2. capital += ("Japan" -> "Tokyo")  
  3. println(capital("France")) 

这段程序建立了一个国家和它们的首都之间的映射表,增加了一个新的绑定("Japan"->"Tokyo"),然后打印了与法国相关的首都。 本例中的声明都是高层次的,也就是说,没有被外加的分号或者类型注释弄得乱糟糟的。实际上,这种感觉就好像那种现代的“脚本化”语言,比如,Perl,Python或者Ruby。这些语言的一个普遍特征,与上例有关的,就是它们都在语法层面上支持“关联映射”。

关联映射非常有用,因为它能让程序易读和清晰。然而,有些时候你或许不赞成它们的这种“均码”哲学,因为你需要用一种更加细粒度地去控制在你程序中用到的映射的属性。Scala可以在你需要的时候提供这种细粒度的控制,因为映射在Scala里并不是语法特性。它们是库抽象,你可以扩展或者改造。

在上面的程序里,你将获得一个缺省的Map实现,不过你也可以很轻松地改变它。比方说,你可以定义个特别的实现,如HashMap或TreeMap,或者你可以特定这个映射必须是线程安全的,混入:mix-in个SynchronizedMap特色:trait。你还可以给映射特定一个缺省值,或你可以重载你创建的映射的任意方法。每个例子里,你都可以如上例所示那样使用同样简单的映射访问语法。

这个例子显示了Scala带给你的方便性和灵活性,可以让你更好的了解Scala是什么。Scala有一整套的方便构件来帮助你快速启动及让你用一种愉悦清晰的状态编程。与此同时,你有信心你不会让语言过度发育。你总可以把程序按你的需要裁剪,因为所有的东西都是基于库模块的,可以依照需要选择和修改。

Scala是什么:培育新的类型

Eric Raymond把大教堂和杂货铺作为软件开发的两个隐喻。 大教堂是几近于完美的建筑物,要花很长的时间建设。一旦建成了,就长时间保持不变。相对来说,杂货铺则天天在被工作其中的人调整和扩展。Raymond的文章中,杂货铺是对于开源软件开发的隐喻。Guy Steele在他的讲话“发展一门语言”中提到同样的差别也可以应用在语言定义中。 Scala更像一个杂货铺而不是大教堂,因为它被设计为让用它编程的人扩展和修改的。Scala并没有提供所有你在一种“完美齐全”语言中可能需要的东西,而是把制作这些东西的工具放在了你的手中。

这儿有个例子。许多程序需要一个能够变得任意大都不会溢出或者由于数学操作而“绕回”的整数类型。Scala在库类Scala.BigInt中定义了这样一个类型。这里有一个使用了那个类型的方法定义,用以计算传入整数的阶乘值:

  1. def factorial(x: BigInt): BigInt =  
  2.     if (x == 01 else x * factorial(x - 1

 现在,如果你调用了factorial(30),你将得到:

265252859812191058636308480000000

BigInt看上去就像一个内建的类型,因为你可以使用整数值和这种类型值的操作符如*和-。然而它只是凑巧定义在Scala标准库中的类。 如果这个类缺失了,可以直接由任意的Scala程序员写一个实现出来,举例来说,通过包装Java的类java.math.BigInteger(实际上,Scala的BigInt就是这么实现的)。

当然,你也可以直接使用Java的类库。但结果却不尽乐观,因为尽管Java允许创建新的类,但这些类总感觉不像原生的语言支持。

  1. import java.math.BigInteger  
  2. def factorial(x:BigInteger): BigInteger =  
  3.     if (x == BigInteger.ZERO)  
  4.         BigInteger.ONE  
  5.     else 
  6.         x.multiply(factorial(x.subtract(BigInteger.ONE))) 

BigInt代表了许多其他类似于数字的类型——大十进制数,复数,分数,置信区间,多项式——诸如此类。一些编程语言原生实现了其中的一些类型。举例来说,Lisp,Haskell和Python实现了大整数;Fortran和Python实现了复数。但是任何语言想要尝试同时实现所有的这些抽象类型将很容易变得太大而难以管理。更进一步,即使如果有这样的语言,总有些应用会使用其他的没支持的数字类型。所以尝试在一种语言里提供所有东西的解决之道不可能很好地伸展。取而代之,Scala允许用户在他们需要的方向上通过定义易用库来发展和改造语言,使得这些特性感觉上好像原生语言支持一样。

培育新的控制结构

前面的例子演示了Scala让你增加新的类型,使得它们用起来方便得像内建类型一样。同样的扩展理念也应用在控制结构上。这种类型的扩展是由Scala的“基于行动类”的并发编程API阐明的。

随着近年多核处理器的激增,为了获取可接受的性能,你将必须在应用中运用更多的并行机制。常常这就意味着重写你的代码来让计算分布到若干并发线程上。不幸的是,创建依赖性的多线程程序在实践中被证明是非常具有挑战性的。Java的线程模型是围绕着共享内存和锁建立的,尤其是当系统在大小和复杂度都得到提升的时候,这种模型常常是不可理喻的。很难说程序里面没有资源竞争或潜藏的死锁——有些东西不是能在测试里面检验得出,而或许只在投入生产后才表现出来。而大致可以认为比较安全的可选方案是消息传递架构,例如在Erlang编程语言中应用的“行动类”方案。

Java伴随着一个丰富的,基于线程的并发库。Scala可以像其他JavaAPI那样使用它编程。然而,Scala也提供了一个实质上实现了Erlang的行动类模型的附加库。

行动类是能够实现于线程之上的并发抽象。它们通过在彼此间发送消息实现通信。每个行动类都能实现两个基本操作,消息的发送和接受。发送操作,用一个惊叹号表示,发送消息给一个行动类。这里用一个命名为recipient的行动类举例如下:

  1. recipient ! msg 

发送是异步的;就是说,发送的行动类可以在一瞬间完成,而不需要等待消息被接受和处理。每一个行动类都有一个信箱:mailbox把进入的消息排成队列。行动类通过receive代码块处理信箱中受到的消息:

  1. receive {  
  2.  case Msg1 => ... // handle Msg1  
  3.  case Msg2 => ... // handle Msg2  
  4.  // ...  
  5. }  

接收代码块由许多case语句组成,每一个都用一个消息模板查询信箱。信箱中第一个符合任何case的消息被选中,并且执行相应的动作。如果信箱中不含有任何符合任何case的消息,行动类将休眠等待新进的消息。

这里举一个简单的Scala行动类实现检查值(cheksum)计算器服务的例子:

  1. actor {  
  2.  var sum = 0 
  3.  loop {  
  4.   receive {  
  5.    case Data(bytes)  => sum += hash(bytes)  
  6.    case GetSum(requester) => requester ! sum  
  7.   }  
  8.  }  
  9. }  

这个行动类首先定义了一个名为sum的本地变量,并赋了初值为零。然后就用receive段落重复等待在消息循环中。如果收到了Data消息,就把发送的bytes取哈希值加到sum变量中。如果收到了GetSum消息,就用消息发送requester!sum把当前sum值发回给requester。requester字段嵌入在GetSum消息里;它通常指出创建请求的行动类。

目前我们并不指望你能完全明白行动类例子。实际上,对于可伸展性这个话题来说这个例子里面最重要的是,不论是actor还是loop还是receive还是发送消息的符号“!”,这些都不是Scala内建的操作符。尽管actor,loop和receive看上去或者表现上都如此接近于控制结构如while或者for循环,实际上它们是定义在Scala的行动类库里面的方法。同样,尽管“!”看上去像是个内建的操作符,它也不过是定义在行动类库里面的方法。所有这四个构件都是完全独立于Scala语言的。

receive代码块和发送“!”语法让Scala看上去更像Erlang里的样子,但是在Erlang里面,这些构件是内建在语言中的,Scala还实现了Erlang其他并发编程构件的大多数,诸如监控失败行动类和超时类。总体来说,行动类已变成表达并发和分布式计算的非常好的办法。尽管它们是定义在库里的,给人的感觉就像行动类是Scala语言整体的部分。

本例演示了你可以向新的方向“培养”Scala语言乃至像并发编程这样的特性。前提是,你需要一个好的架构和程序员来做这样的事。但重要的事情是这的确可行——你可以在Scala里面设计和实现抽象结构,从而快速投入新的应用领域,却仍然感觉像是原生的语言支持。

本文节选自Martin Odersky,Lex Spoon和Bill Venners所著,Regular翻译的《Programming in Scala》的第一章。

【相关阅读】

  1. 学习Scala中的Case类
  2. Groovy创始人:Java面临终结 Scala将取而代之
  3. Scala的类型系统:取代复杂的通配符
  4. Scala的类型系统 比Java更灵活
  5. Java程序员,你为什么要关注Scala
责任编辑:杨鹏飞 来源: Artima
相关推荐

2009-07-08 12:43:59

Scala ServlScala语言

2020-10-31 17:33:18

Scala语言函数

2021-11-09 23:15:20

编程语言本质

2020-08-02 19:55:46

Python编程语言技术

2012-05-16 13:11:28

编程语言开发语言Java

2022-08-17 17:57:37

GoGo语言

2009-07-08 16:42:57

Scala语言设计

2009-07-17 17:05:29

JRuby是什么JRuby

2009-12-11 10:44:00

Scala讲座函数 scala

2010-08-18 08:53:53

Scala

2022-01-25 09:23:58

Linux操作系

2010-09-14 13:22:17

Scala编程指南Scala

2012-09-07 10:02:53

2010-06-18 14:27:52

ACPI是什么

2009-09-16 16:35:08

OSGi是什么OSGi容器

2021-03-15 14:00:56

PythonC语言编程语言

2021-09-01 23:29:37

Golang语言gRPC

2009-02-06 09:08:04

Scala函数语言轻量级

2022-08-26 09:51:49

索引签名编程语言

2010-10-15 10:35:18

点赞
收藏

51CTO技术栈公众号