6.2 SBT
要构建Scala项目,可使用大部分基于JVM的构建工具,包括Apache Maven和Gradle(第4章构建Java项目时使用的构建工具),但Scala提供了自己的构建工具——SBT(Scala Build Tool)。
Scala IDE默认并不支持SBT。稍后你将看到,这不是问题,因为可以反过来做:让SBT支持Eclipse。我们将使用SBT新建一个项目,并安装一个能够创建并更新Eclipse项目的SBT插件。本节介绍如下与SBT相关的主题:
- 安装SBT;
- 新建基于SBT的项目;
- 添加在SBT中添加与Eclipse相关命令的SBT插件。
6.2.1 安装SBT
要安装SBT,请访问http://www.scala-sbt.org,并下载用于你使用的操作系统的最新版本。
对于Windows操作系统,提供了负责安装并设置环境变量Path的MSI安装程序;对于其他操作系统,必须下载并解压缩一个归档文件(ZIP或TGZ),再将其位置添加到环境变量Path中。
与Gradle一样,SBT命令也可以从命令行执行,方法是将命令指定为参数。SBT的独特之处在于,它还提供了一个交互式shell。在交互式模式下运行SBT时,可以交互的方式执行SBT命令;另外,这个shell还支持自动补全——你只需按Tab键即可。
要检查安装情况,可在命令提示符(Windows)或终端(macOS和Linux)中输入sbt并按回车,这将以交互模式启动SBT。
6.2.2 创建基于SBT的Eclipse IDE项目
前面说过,Scala IDE for Eclipse插件存在的一个严重问题是,它当前不支持SBT。通过在SBT中安装一个插件,可从SBT生成Eclipse项目文件。要新建可在安装了Scala IDE插件的Eclipse IDE中打开的基于SBT的项目,可采取如下工作流程。
(1) 使用项目模板新建一个基于SBT的项目。
(2) 在SBT中添加插件sbteclipse。
(3) 在SBT中,使用插件sbteclipse生成一个新的Eclipse IDE/Scala IDE项目。
- 新建SBT项目
要新建项目,最简单的方式是让SBT生成一个Hello World项目(其中包含一个空的构建文件)。必须在Eclipse IDE的workspace目录(Eclipse IDE用来存储项目的目录)中执行创建新项目的命令。如果你不确定这个目录的位置,可启动Eclipse并尝试创建一个Java项目,这样将显示目录workspace的路径。要新建一个基于SBT的项目,请按如下步骤操作。
- 启动命令提示符(Windows)或终端(macOS和Linux),并切换到目录workspace,再输入如下命令并按回车:
sbt new sbt/scala-seed.g8
首次执行这个命令时,SBT会下载一些依赖项。过段时间后,它将要求你提供项目名。请输入Akka Quotes并按回车。这将在目录
akka-quotes中新建一个项目。切换到目录akka-quotes,再输入
sbt并按回车,以启动SBT的交互式shell。- 输入下面的命令并按回车来尝试运行生成的项目:
run
同样,首次运行项目时,SBT将下载一些依赖项。下载完毕后,你将在控制台中看到一条“hello”消息:

输入命令exit并按回车,以退出这个交互式shell。
用来生成这个项目的模板基于最新且稳定的Scala版本,因此必须检查安装的Scala IDE版本是否支持这个版本。为此,在Eclipse IDE中选择菜单Window>Preferences。
在左边的列表中,找到并展开条目Scala,再选择其中的条目Installations。将安装的Scala IDE支持的Scala版本都记录下来;在我的系统中,支持的版本为Scala 2.11.8和Scala 2.10.6。在文本编辑器中,打开目录akka-quotes中生成的构建文件built.sbt。在我的系统中,这个文件类似于下面这样:
import Dependencies._lazy val root = (project in file(".")).settings(inThisBuild(List(organization := "com.example",scalaVersion := "2.12.1",version := "0.1.0-SNAPSHOT")),name := "Hello",libraryDependencies += scalaTest % Test)
如果其中的变量scalaVersion的值包含在安装的Scala IDE支持的Scala版本中,就万事大吉。否则,你就必须将变量scalaVersion的值修改为相应的版本。对我来说,必须将这个变量修改成下面这样:
scalaVersion := "2.11.8",
如果必须修改这个变量的值,请在修改后从命令行运行如下命令,以清理并重新编译项目:
sbt clean run
SBT将使用修改后的Scala版本重新编译项目。鉴于这个模板是基于最简单项目的,这通常可行——不会出现任何问题。
使用本章介绍的工具链时,如果出现严重的版本冲突问题,请尝试下载本书使用的版本,等你有了足够多的经验后,再切换到最新的版本。
- 加载插件SBTEclipse
要获悉你必须安装该插件的哪个版本,请访问该插件的项目页面http://github.com/typesafehub/sbteclipse):

这个GitHub项目页面提供了如何在项目中添加这个插件的说明。你应查找以addSbtPlugin打头的行;我访问这个项目页面时,这行的内容如下:
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin"% "5.1.0")
在项目akka-quotes的子目录project中,新建一个名为plugins.sbt的文件,并将前述一行内容复制并粘贴到这个文件中,让SBT知道这个项目需要插件SBTEclipse。
务必将这个文件存储在子目录project中,否则SBT将找不到它。
- 使用SBTEclipse生成新的Eclipse IDE项目
切换到目录akka-quotes,输入sbt并按回车以再次启动SBT交互式shell。
SBT将下载并激活插件SBTEclipse。从现在开始,在这个项目目录中启动SBT后,将能够创建或更新Eclipse IDE/Scala IDE项目。执行插件sbteclipse添加的如下命令:
eclipse
插件sbteclipse将在这个SBT项目的目录中生成项目文件,而安装了Scala IDE插件的Eclipse IDE能够导入的这些文件。
- 在Eclipse IDE中导入生成的项目
返回到Eclipse IDE(如果它没有运行,就启动它)。为导入SBTEclipse生成的项目,请执行如下步骤。
(1) 在屏幕左边的Package Explorer的空白区域右击鼠标,并选择Import…。
(2) 将出现Import对话框,让你选择一个导入向导。请选择General>Existing Projects into Workspace,并单击按钮Next。
(3) 单击Select root directory旁边的按钮Browse…,选择目录workspace下的子目录akka-quotes,并单击OK按钮。
(4) 导入向导对话框的项目列表中将包含项目akka-quotes。单击按钮Finish关闭这个对话框。
这个项目将出现在Package Explorer中。在Package Explorer中,选择文件src/main/Scala> example>Hello.scala,再按Ctrl + F11运行这个文件。你也可单击工具栏中的Run按钮或选择菜单Run>Run来运行这个文件。如果一切顺利,你将在Console选项卡中看到问候“hello”:

6.2.3 Scala编译器(scalac)
构建项目时,SBT将替我们调用Scala编译器scalac,因此我们无需直接调用它。但你必须知道,SBT使用的是scalac,而不是前一章一直使用的命令scala。
最重要的差别在于,Scala编译器像Java编译器javac一样,要求将代码封装在类中。命令scala通过在幕后创建一个不可见的类来满足这种要求,但编译器scalac不会这样做,因此在Scala IDE中编写由SBT构建的Scala代码时,必须定义类并将代码添加到其中。
为此,有两种办法:
- 创建包含方法
main()的单例对象; 让单例对象扩展特质
App。创建包含方法
main()的单例对象
这与Java很像。鉴于Scala没有与Java访问修饰符static等价的东西,因此必须使用单例对象。方法main()必须将String数组(Array[String])作为输入参数,且返回类型为Unit(类似于Java关键字void):
object MainObject {def main(args: Array[String]): Unit = {println("Executable code here...")}}
- 创建扩展特质App的单例对象
可不给单例对象添加方法main(),而使用Scala提供的特质App。App特质的不同寻常之处在于,你不能重写其中的任何方法,也不能在实现了特质App的类中添加方法main()。相反,你只需在类中直接添加可执行的代码,就像它们是类的主构造函数的可执行代码一样:
object MainObject extends App {println("Executable code here...")}
本章将采用这种方法。
