博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《深入理解Scala》——第2章,第2.1节学习使用Scala交互模式(REPL)
阅读量:6983 次
发布时间:2019-06-27

本文共 3761 字,大约阅读时间需要 12 分钟。

本节书摘来自异步社区《深入理解Scala》一书中的第2章,第2.1节学习使用Scala交互模式(REPL),作者[美]Josh Suereth,更多章节内容可以访问云栖社区“异步社区”公众号查看

第2章 核心规则

深入理解Scala
本章包括的内容:
• 使用Scala交互模式(Read Eval Print Loop 简称REPL)
• 面向表达式编程
• 不变性(Immutability)
• Option类
本章内容覆盖了每个新Scala开发者都需要知道的几个主题。本章不会深入到每个主题里,但是会讲到可以让你自己去接着探索的程度。你将学会使用REPL,学会如何利用这个工具做软件的快速原型开发。然后我们会学到面向表达式编程,并从另一个视角来看控制结构是怎么回事。在此基础上,我们来研究不变性,研究不变性为什么能帮助我们极大地简化程序,并且能帮助程序在并发环境下更好地运行。

2.1 学习使用Scala交互模式(REPL)

深入理解Scala
Scala提供了很多学习材料帮助你学习核心语言内容,有很多在线的教程、示例和项目可以去研究。但是Scala提供的最重要的一个工具是交互模式(REPL)。REPL是一个交互式解释器,可以即时编译、运行代码并返回结果。假定你已经在机器上装好了Scala,也设置了正确的路径,那么在命令行下运行scala命令就可以启动Scala REPL。启动Scala REPL后屏幕上会输出如下内容:

4c56f5087e05024b80c957b776f8b83497692227

后面的代码示例中,我会用scala>提示这是输入到REPL的内容。接下来的一行是REPL的输出。我们在REPL里快速做几个例子,看看会得到什么输出。

7c456b6dcdaf7f5c2576f0b8b09d85b59d11bc6d

你应该注意到了在我们输入解释器的每个语句后,它会输出一行信息,类似res0: java.lang.String = Hello。输出的第一部分是REPL给表达式起的变量名。在这几个例子里,REPL为每个表达式定义了一个新变量(res0到res3)。输出的第二部分(:后面的部分)是表达式的静态类型。第一个例子的类型是java.lang.String,最后一个例子的类型则是scala.util.matching.Regex。输出的最后一部分是表达式求值后的结果的字符串化显示。一般是对结果调用toString方法得到的输出,JVM给所有的类都定义了toString方法。

图2.1 REPL的返回值

f150121510e31988962ee34c46c4a409f8fc13dc

如你所见,REPL是一种测试Scala语言及其类型系统的强有力手段。不仅如此,大部分构建工具都提供了机制让你能加载当前工程的classpath,然后启动REPL。这意味着你可以在REPL里访问工程中引用的库和你自己的代码。你能够在REPL里调用API和访问远端服务器。这是很棒的快速测试Web服务或REST API的方法,也导向我称为实验驱动开发(Experiment Driven Development)的方法。

2.1.1 实验驱动开发

实验驱动开发就是开发者在写测试或生产代码前,先花点时间在交互环境或REPL里做实验。这可以给你时间全面理解你需要打交道的软件或库的外部接口,并对其API的优点和缺点得到点切身体会。这是学习新发布的Web服务或RESTful API或最新的Apache库的极好办法,甚至可以用来学习你同事刚刚写出来的东西。在理解了API是怎么工作后,你就能更好地写自己的代码,或者开始写测试,如果你遵循测试驱动开发的话。
现在推动开发人员拥抱测试驱动开发(TDD)的呼声很高。TDD要求开发者先写单元测试,然后写实现类。在你开始写测试前,你并不总是很清楚自己的API要定义成什么样的。TDD的一个组成部分就是通过写测试来定义API,这样你可以在(用户的)上下文里来看你的代码,可以感觉一下你自己愿意不愿意用你自己写的API。由于表达力(较差)的原因,强类型语言在应用TDD时可能会比动态语言碰到更多麻烦。实验驱动开发将“定义API”这个步骤向前期推动一步,提前到了写测试代码之前。REPL帮助开发者确保其设计的API在类型系统里能表达得出来。
Scala是一种语法非常灵活的强类型语言,因此有时候需要用点手段欺骗类型系统才能达成你真正想要的API设计。因为很多开发者缺乏强类型理论基础,所以经常需要更多的实验。实验驱动设计(Experiment Driven Design)让你在REPL里结合类型系统进行实验,以便为你的API提炼出最有效的类型定义。实验驱动设计主要用在给代码里添加大特性或领域对象的时候,不适合在添加新方法或者修bug时使用。
实验驱动设计在你定义领域特定语言时(DSL)也能帮上大忙。领域特定语言是用于特定领域的伪编程语言,这种语言专门用来解决手头的某个领域,比如说,从数据库里查询数据。DSL可以是内部的,在很多Scala库里都能看到的;也可以是外部的,比如SQL。在Scala社区,库开发者圈子里非常流行为自己的库创建一种DSL。比如Scala的actors库定义了一种线程安全的发送和接收消息的DSL。
用Scala定义DSL的挑战之一在于有效地利用类型系统。设计良好的类型安全的DSL不仅应该富有表达力、易读,而且应该能在编译期而不是运行期捕捉到很多编程错误。同时静态类型信息也可以极大地提高性能。REPL不仅能用来实验怎样表达一个特定领域,而且能帮助你确定你得表达式是否能编译。进行Scala开发时,有些人采用下面这种创造性的流程。
• 在REPL里实验API设计。
• 把能工作的API拷贝到项目文件。
• 为API写单元测试。
• 修改代码直到测试通过。
有效地使用实验驱动开发能够极大地提高你的API的质量。也会帮你在推进过程中更适应Scala的语法。不过这种做法有个大问题,就是并非所有能用Scala表达的API都能在REPL里表达。这是因为REPL是积极(eagerly)解析输入,即时解释执行的。

2.1.2 绕过积极(eaglerly)解析

Scala REPL尝试尽可能快地解析输入。这个特点加上其他一些限制,意味着有些东西很难甚至是无法在REPL里表达的。其中一个难以表达的重要的功能是伴生对象和伴生类。
伴生对象和伴生类是一组用完全一样的名字定义的对象和类。用文件编译的方式很容易实现,就像这样简单的声明对象和类:

70a56465268ed8da929be88e023a7f6c4cf89dcf

这些语句在REPL里也能执行,但是它们不会像真的伴生类那样起作用。为证明这一点,我们来做一些只有伴生对象能做,普通对象做不了的事:访问类的私有变量。

2ab00448f93093f9ed99c4200862564e0ffcf72a

为了解决这个问题,我们需要把这些对象嵌入解释器里某个能访问到的其他作用域里。我们现在来把它们放入某个作用域里,以便能同时解释/编译类和伴生对象。

819f00b60252fc427139bc76c4bbd832a91b6f82

我们在这创建了一个holder对象。这给了我们一个可访问的作用域,也把REPL的编译推迟到holder对象关闭的时候。这样我们就可以在REPL里测试/定义伴生对象了。

即使绕过了积极解析,也还有一些语言特性无法在REPL里重现。大多数这种问题都跟包、包对象、包可见性约束等问题有关。尤其是你无法像在源代码文件里一样有效地在REPL里创建包和包对象。这也意味着其他跟包有关的语言特性,特别是使用private关键字实现的可见性限制也无法在REPL里表达。包通常用来为你的代码设定命名空间,以便与你可能使用的其他类库分开。通常情况下你不需要在REPL里用到它,但是可能有些时候你需要把玩一些Scala的高级特性,比如包对象和隐式解析(implicit resolution),这时你可能会想做点实验驱动开发。但是这种场景下,你无法在REPL里去表达。

33d6e436d1026b46cfa045a8336e92e385070524

请不要绝望。如我之前说过的,大部分构建工具可以让你启动一个针对你当前工程的Scala REPL。作为最后的手段,你可以在Scala文件里把玩那些高级概念,重编译然后重启REPL会话。

另外还有个工具叫做JRebel(),它可以动态地在运行中的JVM里重载类文件。JRebel团队非常慷慨地为Scala中的使用提供了免费许可。利用这工具结合某种形式的持续编译—大部分Scala构建工具都提供的这一特性—你可以在修改工程文件后立刻在REPL会话里得到修改后的行为。对于maven-scala-plugin,持续编译的细节见其网站:。Simple Build Tool()(译者注:已经搬迁到github了,)提供了CC任务来做持续编译。不管用哪种构建工具都必须和JRebel类加载器集成以便实现动态类重载。这个技巧有点过于细节,而且可能会变,所以如果需要帮助请参考你用的构建工具的文档或者JRebel网站。
在尝试创建大而复杂的系统前,你可以先利用REPL来实验Scala代码,获得一些真实的感觉。软件开发中,在开发一个新特性前,对当前系统得到一个稍微深入一些的理解(而不只是草草看过)往往是很重要的。Scala REPL可以让你投入最少的时间达成对系统的理解,还可以提高你的开发技巧。本书全文穿插着很多REPL的例子,因为它是教学Scala的最好工具。我经常完全通过REPL运行示例,而不是采用Java开发时的标准做法,先写main方法或者单元测试。
REPL也是开始学习面向表达式编程的极佳方法。

转载地址:http://bxxpl.baihongyu.com/

你可能感兴趣的文章
SQL Server扩展事件(Extended Events)-- 将现有 SQL 跟踪脚本转换为扩展事件会话
查看>>
传说中的裸奔节--认识及体验CSS
查看>>
二十年后的回眸(2)——顺风顺水的前三年
查看>>
烂泥:为KVM虚拟机添加网卡
查看>>
数据驱动安全架构升级---“花瓶”模型迎来V5.0(二)
查看>>
Sql Server 常用日期格式
查看>>
让“云”无处不在-Citrix Xenserver之一 环境搭建
查看>>
CentOS 5.5下LVM的分区管理
查看>>
Vsftp与PAM虚拟用户
查看>>
GoogleAppEngine是什么?
查看>>
利用 UML 进行实体关系建模
查看>>
WCF中的Stream操作
查看>>
.NET实现之(WebService数据提供程序)
查看>>
Spread for Windows Forms快速入门(8)---单元格中用户动作触发的事件
查看>>
XXX管理平台系统——概要
查看>>
常用思科设备图标(JPG+矢量图)
查看>>
倒排列表求交集算法 包括baeza yates的交集算法
查看>>
微信 登录 Scope 参数错误或没有 Scope 权限
查看>>
C# 温故知新 基础篇(7) 接口<思维导图>
查看>>
jQuery Makes Parsing XML Easy[转]
查看>>