1

上手Scala


1.1 为什么选Scala?15
1.2 为什么选择本书?16
1.3 本书如何组织17
1.4 代码片段和样例18
1.5 在线资料20

package app
object MinimalApplication extends cask.MainRoutes {
  @cask.get("/")
  def hello() = {
    "Hello World!"
  }

  initialize()
}
</> 1.1.scala

Snippet 1.1: 一个小型Scala web应用,我们将在这本书里遇到诸如此类的样例程序。

上手Scala 以基于项目的风格,教会你在实践中如何使用Scala编程语言。我们的目标是在广泛的实际应用中使用Scala,发展专业知识。本书带领你使用Scala,从“hello world”出发,构建交互式网站,并发web爬虫,直至分布式应用。

书里覆盖了任何人想要专业地使用Scala都必须具备的坚实技能:处理文件,数据序列化,查询数据库,并发等等。上手Scala 会指导你完成几个较复杂的项目,这些项目可能反映在一个软件工程师日常工作构建出的应用里。这将让你专业地使用Scala快速上手。

上手Scala 假设你已经是一位有另一种编程语言经验的软件开发者,想要快速用Scala开始工作并具备生产力。如果你属于下列类别之一,这本书就对你有帮助。

  • 使用软件做大数据处理,比如Apache Spark,它就是Scala编写的

  • 加入使用Scala的公司,需要快速上手

  • 使用Ruby或者Python时遇到性能瓶颈,要寻找运行更快速的编译语言

  • 用Java或者Go工作,正寻找开发更敏捷的语言

  • 已经有Scala使用经验,但是想要技能更上一层楼

  • 成立一家科技初创公司,正寻找一门可以伴随公司成长而扩展的语言

注意这本书不是为了教完全的新手如何编程。我们希望你熟悉基本编程概念:variables, integers, conditionals, loops, functions, classes等等。当这些概念在Scala中表现不同时我们会详细讨论,但是期望你对它们如何工作已有基本理解。

1.1 为什么选Scala?

Scala是一门简洁的高等语言,它结合了面向对象和函数式编程风格。Scala的静态类型帮助复杂应用避免bug,并且它的 JVM (Java Virtual Machine) 运行时 允许你轻松使用Java生态的工具和库来构建高性能系统。

Scala是一个通用目的编程语言,已经被广泛地用于解决各领域的问题:

  • Twitter社交网络用Scala编写大部分后端系统
  • Apache Spark大数据引擎是用Scala实现的
  • Chisel硬件设计语言构建在Scala之上

尽管Scala从未像Python,Java,C++那样成为主流语言,但它仍然在一大批公司以及大量开源项目中使用。

1.1.1 具有动态的编译语言

Scala有脚本语言的便利性,编译语言的高性能和扩展性,它可以从一行代码片段扩展到百万行产品的代码库。Scala的简洁性使得制作快速原型成为乐趣,同时经过编译器优化以及JVM运行时加持,提供了优秀性能去支撑生产环境的高负载。Scala让你重用已有技能,专注手上实际任务,而不是强迫你为每个案例学习不同的语言。

1.1.2 轻松保证安全与正确性

Scala函数式编程风格和类型检查编译器帮助过滤掉一切对象类bug和缺陷,让你把时间用在开发用户需要的功能上。Scala将错误和问题在编译期提前暴露,而不是让你在生产环境中和 TypeErrorNullPointerException 做斗争。因此你可以提前解决问题,带着自信部署代码,不再由于愚蠢的bug或者细小的错误造成的宕机而在夜里惊醒。

1.1.3 广泛而具有深度的生态系统

作为运行在JVM上的语言,Scala能够接入具有巨大标准库和工具的Java生态系统,这些库和工具是你在构建产品应用时无可避免会使用到的。无论你是在寻找Protobuf解析器,机器学习工具包,database连接库,亦或是定位瓶颈的profiler,生产部署的监控工具。Scala给你提供需要把代码带到生产环境部署的一切东西。

1.2 为什么选择本书?

上手Scala 的目标是让使用Scala编程的软件工程师尽可能快地具备生产力。

1.2.1 不仅仅是Scala语言本身

大多数Scala书籍聚焦在教授语言本身。然而当需要搭建网站、和第三方API集成、或者构造不简单的应用时,懂得语言的细枝末节是没必要的,也是不够的。上手Scala 就是要填上那块空白。

这本书超越Scala语言本身,涵盖了各种各样的工具和库,这些是你在典型的实际工作中使用Scala时所需要的。上手Scala 在最大程度上保证你可以获得使用Scala所必备的支持技能。

1.2.2 聚焦实际项目

上手Scala 的章节是基于项目的:每一章使用Scala构建出一个小项目,在实际工作中能够发挥立竿见影的效果。后续的 练习 (1.5.3) 强化你的知识,并测试你在该主题习得的经验。

上手Scala 课程中,你将通过诸如以下项目:

  • 增量静态网站生成器
  • 使用Github API开发的项目迁移工具
  • 并发网络爬虫
  • 带数据库的交互式聊天网站
  • 实时网络文件同步器
  • 编程语言解释器

这些项目有两个目的:一是巩固你在每个章节学到的工具和技术,二是构建你的工具箱。API客户端、网络爬虫、文件同步器、静态网站生成器、网络应用、以及你将构建的其他项目,这些都是用Scala实现的真实项目。完成本书的学习后,你在用Scala开展专业工作时,已经具备了一些特定任务场景的实际经验。

1.2.3 代码优先

上手Scala 开始于编码,结束于编码。你在本书学到的概念被超过140个可执行代码样例生动展示,每一章末尾都有一些练习,习题都有完备的、可执行的解决方案供参考。上手Scala 不仅仅是知识来源,同样可以作为你在未来启动任何项目时的指导手册。

上手Scala 认为读者的时间很宝贵。每一章节、段落都经过仔细编织,教授你必需概念后,带领你最终构建可运行的应用。你甚至可以将构建出的代码演化成你的下一个项目、工具、或者产品。

1.3 本书如何组织

本书按照四部分组织:

Part I Scala导论 是自成一体的Scala介绍。我们假设你已经有一些编程背景,然后帮助你迁移既有知识并应用于Scala编程中。经过熟悉Scala后,开始在各种各样的有趣用例中使用它。

Part II Local Development 探索核心工具和技术,它们是编写运行在单机上的Scala应用所必备的。我们会涵盖算法、文件与子进程管理、数据序列化、脚本以及构建管道。这个部分一步步构建出终极项目:使用Scala编写高效、增量的静态网站生成器。

Part III Web Services 包含了服务器与客户端,系统与服务的世界。我们将探索在客户端、服务器中如何使用Scala,通过HTTP或者WebSocket交换HTML和JSON。这个部分一步步构建出两个终极项目:一个并行网站爬虫和一个带数据库的交互式聊天网站,它们代表着你在分布式的网络环境中使用Scala时,可能遇到的通用案例。

Part IV Program Design 探索架构Scala应用的不同方式,去解决实际问题。这个部分一步步构建出另外 两个终极项目:一个实时文件同步器以及一个编程语言解释器。这些项目将让你看到Scala非比寻常的使用方式,一种优雅且符合直觉的方式实现有挑战的应用。

每个部分分解为五章,每章有自己的小项目和练习。每章包含在线代码片段和完整程序,可以 通过链接访问 (1.5) 它们,再复制粘贴到你的编辑器或者命令行中。

本书用到的库和工具有完善的在线文档。上手Scala 不会对每个主题都介绍一番,但是会把你链接到在线文档以便你可以了解更多。每章会标记可备选的库和工具,你可能在实际使用Scala时会碰到它们。

1.3.1 章节依赖图

尽管 上手Scala 旨在你按照从头到尾的顺序阅读,但是你也可以选择一些特定话题来阅读。下列图表展示了章节依赖,你可以规划自己的阅读路径,专注学习你最感兴趣的东西。

G cluster_1 Part I: Scala导论 cluster_2 Part II: Local Development cluster_3 Part III: Web Services cluster_4 Part IV: Program Design p1 Chapter 1: 上手Scala Chapter 2: 搭建环境 Chapter 3: Scala基础 Chapter 4: Scala集合 Chapter 5: Scala特性 6 Chapter 6 Implementing Algorithms in Scala p1->6 7 Chapter 7 Files and Subprocesses 6->7 11 Chapter 11 Scraping Websites 6->11 19 Chapter 19 Parsing Structured Text 6->19 8 Chapter 8 JSON and Binary Data Serialization 7->8 9 Chapter 9 Self-Contained Scala Scripts 7->9 12 Chapter 12 Working with HTTP APIs 8->12 14 Chapter 14 Simple Web and API Servers 8->14 16 Chapter 16 Message-based Parallelism with Actors 8->16 10 Chapter 10 Static Build Pipelines 9->10 13 Chapter 13 Fork-Join Parallelism with Futures 12->13 15 Chapter 15 Querying SQL Databases 14->15 17 Chapter 17 Multi-Process Applications 16->17 18 Chapter 18 Building a Real-time File Synchronizer 17->18 20 Chapter 20 Implementing a Programming Language 19->20

1.4 代码片段和样例

我们会在书中展示大量代码。我们希望读者跟随这些代码,贯穿整个章节:这意味着打开你的终端和编辑器,保持工作,输入并执行代码样例。确保你执行代码并看到它工作,感受代码如何表现。本节将会带你领略代码片段和样例。

1.4.1 命令行片段

我们的命令行代码片段需要你使用 bash 或者兼容的shell,比如 shzsh来运行。在Windows中,可以通过 Windows Subsystem for Linux 来使用shell。这些shell表现相似,我们将在代码片段前加 $ 来指示输入Unix shell的命令:

$ ls
build.sc
foo
mill

$ find . -type f
.
./build.sc
./foo/src/Example.scala
./mill
</> 1.2.bash

每个用例里,加 $ 前缀的行是输入的命令,紧跟在下面的是命令的预期输出,下一个命令会用空行隔开。

1.4.2 Scala REPL代码片段

编写Scala代码最简单的方式,是使用Scala REPL (Read-Eval-Print-Loop)。这是一个交互式的命令行工具,你可以输入并执行Scala代码,立即看到它的输出。本书使用 Ammonite Scala REPL ,加了 @ 前缀的代码片段将被输入到REPL中:

@ 1 + 1
res0: Int = 2

@ println("Hello World")
Hello World
</> 1.3.scala

每个案例中,输入的命令是加了 @ 前缀的行,接下来的行是命令的预期输出。表达式的估值可以间接打印在终端,比如案例中的 1 + 1,或者通过 println 直接打印。

Ammonite Scala REPL支持输入多行,用 {} 包裹它们:

@ {
  println("Hello" + (" " * 5) + "World")
  println("Hello" + (" " * 10) + "World")
  println("Hello" + (" " * 15) + "World")
  }
Hello     World
Hello          World
Hello               World
</> 1.4.scala

这有助于我们想确保代码作为整体单元来运行,避免了用户逐行输入时,步骤之间会有执行延迟。Ammonite的安装会在 Chapter 2: 搭建环境 提及。

1.4.3 源文件

本书许多样例依赖磁盘上的源文件:它们可能作为脚本运行,或者作为更大项目的一部分编译后运行。所有这样的代码片段在右上角标有文件名:

build.scimport mill._, scalalib._

object foo extends ScalaModule {
  def scalaVersion = "2.13.8"
}</> 1.5.scala
foo/src/Example.scalapackage foo
object Example {
  def main(args: Array[String]): Unit = {
    println("Hello World")
  }
}</> 1.6.scala

1.4.4 代码变动

我们通过 diffs 渲染文件的变动。代码变动diff是一个代码片段,其中 +- 分别指示了增加的和删除的行:

   def hello() = {
-    "Hello World!"
+    doctype("html")(
+      html(
+        head(),
+        body(
+          h1("Hello!"),
+          p("World")
+        )
+      )
+    )
   }
</> 1.7.scala

上面的diff代表删除一行 - "Hello World!" - 以及原地增加9行代码。这有助于你聚焦在程序的变动上。在我们完成一系列变动走查后,为了容易参考,我们将展示被修改文件的完整代码。

1.5 在线资料

下列Github仓库是 上手Scala 在线中心,包括所有笔记、勘误表、讨论、资料、以及代码样例:

1.5.1 代码片段

本书的代码片段放在 snippets/ 文件夹下:

代码片段的tag如下:

  • </> 1.1.scala

可通过下列URL来获取:

这方便你复制粘贴代码,而不用繁琐地手动输入它们。注意有些代码片段本身不可执行,例如包含diff的片段。本书同时提供了完整的 可执行代码样例 (1.5.2)。

1.5.2 可执行代码样例

本书的代码是可执行的,按照每章代码片段的指导,你可以运行并复现所有出现过的样例。上手Scala 同样提供了完整可执行的在线样例:

handsonscala/handsonscala 仓库中每个样例都有一个 readme.md 文件,其中包含运行该样例的命令。贯穿本书,我们使用如下醒目标注引用在线样例:

See example 6.1 - MergeSort

我们经常从初始代码片段开始逐渐深入每一章,发生修改后用 代码变动 (1.4.4) 或者 代码片段 (1.5.1) 展示,并产生最终程序。我们没有完整展示中间程序,因为这会非常啰嗦,但这些可执行代码样例让你有机会看到每个修改阶段的完整可运行代码。

每个样例是完全自成一体的,参考 Chapter 2: 搭建环境 ,你可以运行目录中 readme.md 里的命令,然后看到代码执行。你可以用这些代码作为实验基础,在其之上构建你自己的程序和应用。本书所有代码片段和样例用MIT license授权。

1.5.3 练习

从第五章开始,每章末尾搭配一些练习:

Exercise: Tries can come in both mutable and immutable variants. Define an ImmutableTrie class that has the same methods as the Trie class we discussed in this chapter, but instead of a def add method it should take a sequence of strings during construction and construct the data structure without any use of vars or mutable collections.

See example 6.7 - ImmutableTrie

这些练习的目标是把你学到的东西综合成有用的技能。一些练习要求你利用所学去编写新代码,另外一些要求你修改章节中出现过的代码,还有一些要求你结合多章技术才能取得成果。它们将帮助你巩固学到的东西,构建坚实的基础,以便于你应用到未来的任务和挑战中。

这些练习的解决方案也是可执行代码样例,可以在线获取。

1.5.4 资源文件

Github仓库 handsonscala/handsonscala 还包含资源文件 (resources):有些代码运行时会用到一些抽样数据文件。可通过以下获取:

在需要用到这些资源文件的章节中,你可以通过链接下载它们。在浏览器页面中点击 Raw 按钮查看原始文件内容,然后使用 Cmd-S/Ctrl-S 保存文件到你的磁盘,以便于代码运行时找到它们。

1.5.5 在线讨论

关于本书的进一步帮助或讨论,请访问我们的在线聊天室。在那里你也许能和其他读者交流笔记,或者讨论书中的主题:

有的章节末尾还有特定讨论频道链接。你可以使用这些频道讨论章节的特定主题,而不必和其他讨论混在一起。特定章节讨论频道的完整列表,可以通过下列URL找到:

1.6 总结

第一章让你对本书内容有所了解,以及阅读它可以预期的收获。现在我们已经介绍了本书的结构、组织、编排原理,我们将开始搭建Scala开发环境,在全书剩余部分里,你将会一直使用这个环境。

Discuss Chapter 1 online at https://www.handsonscala.com/discuss/1