Scala解释器

启动Scala解释器的步骤如下:

●安装Scala

●确保scala/bin目录位于系统PATH中。

●在你的操作系统中打开命令行窗口。

●键入scala并按Enter键。

提示:不喜欢命令行?你也可以通过其他方式运行Scala解释器,参见 http://horstmann.com/scala/install

现在,键入命令,然后按Enter键。每一次,解释器都会显示出结果。例如,当你键入“8 * 5 + 2”(如下面加粗的文字),将得到42

scala> 8 * 5 + 2

res0: Int = 42

答案被命名为res0,你可以在后续操作中使用这个名称:

scala> 0.5 * res0

res1: Double = 21.0

scala> "Hello," + res0

res2: java.lang.String = Hello, 42

正如你所看到的,解释器同时还会显示结果的类型——拿本例来说就是IntDoublejava.lang.String

你可以调用方法。根据启动解释器的方式的不同,你可能可以使用Tab键补全而不用完整地手工键入方法名。你可以试着键入res2.to,然后按Tab键,如果解释器给出了如下选项:

toCharArray toLowerCase toString toUpperCase

说明Tab键补全功能是好的。接下来键入U并再次按Tab键,你应该就能定位到单条补全如下:

res2.toUpperCase

按下Enter键,结果就会被显示出来。(如果在你的环境中无法使用Tab键补全,那你就只好自行键入完整的方法名了。)

同样地,可以试试按方向键。在大多数实现当中,你将看到之前提交过的命令,并且可以进行编辑。用Del键将上一条命令修改为:

res2.toLowerCase

正如你所看到的,Scala解释器读到一个表达式,对它进行求值,将它打印出来,接着再继续读下一个表达式。这个过程被称做读取-求值-打印-循环,即REPL

从技术上讲,scala程序并不是一个解释器。实际发生的是,你输入的内容被快速地编译成字节码,然后这段字节码交由Java虚拟机执行。正因如此,大多数Scala程序员更倾向于将它称做“REPL”。

提示:REPL是你的朋友。即时反馈鼓励我们尝试新的东西;而且,如果它跑出你想要的效果,你会很有成就感。

同时,打开一个编辑器窗口也是个不错的主意,这样你就可以将成功运行的代码片段复制、粘贴出来供今后使用。同样地,当你尝试更复杂的示例时,你也许会想要在编辑器中组织好以后再贴到REPL

声明值和变量

除了直接使用res0res1等这些名称之外,你也可以定义自己的名称:

scala> val answer = 8 * 5 + 2

answer: Int = 42

你可以在后续表达式中使用这些名称:

scala> 0.5 * answer

res3: Double = 21.0

val定义的值实际上是一个常量——你无法改变它的内容:

scala> answer = 0

<console>:6: error: reassignment to val

如果要声明其值可变的变量,可以用var

var counter = 0

counter = 1 // OK,我们可以改变一个var

Scala中,我们鼓励你使用val——除非你真的需要改变它的内容。JavaC++程序员也许会感到有些意外的是,大多数程序并不需要那么多var变量。

注意,你不需要给出值或者变量的类型,这个信息可以从你用来初始化它的表达式推断出来。(声明值或变量但不做初始化会报错。)

不过,在必要的时候,你也可以指定类型。例如:

val greeting: String = null

val greeting: Any = "Hello"

说明:在Scala中,变量或函数的类型总是写在变量或函数名称的后面。这使得我们更容易阅读那些复杂类型的声明。

当我在ScalaJava之间来回切换的时候,我发现我经常无意识地敲出Java方式的声明,比如String greeting,需要手工改成greeting: String。这有些烦人,但每当我面对复杂的Scala程序时,我都会心存感激,因为我不需要再去解读那些C风格的类型声明。

说明:你可能已经注意到,在变量声明或赋值语句之后,我们并没有使用分号。在Scala中,仅当同一行代码中存在多条语句时才需要用分号隔开。

你可以将多个值或变量放在一起声明:

val xmax, ymax = 100 // xmaxymax设为100

var greeting, message: String = null

// greetingmessage都是字符串,被初始化为null

常用类型

到目前为止你已经看到过Scala数据类型中的一些,比如IntDouble。和Java一样,Scala也有7种数值类型:ByteCharShortIntLongFloatDouble,以及1Boolean类型。跟Java不同的是,这些类型是类。Scala并不刻意区分基本类型和引用类型。你可以对数字执行方法,例如:

1.toString() // 产出字符串"1"

或者,更有意思的是,你可以:

1.to(10) // 产出Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

(我们将在第13章介绍Range类,现在你只需要把它当做一组数字就好。)

Scala中,我们不需要包装类型。在基本类型和包装类型之间的转换是Scala编译器的工作。举例来说,如果你创建一个Int的数组,最终在虚拟机中得到的是一个int[]数组。

正如你在1.1节中看到的那样,Scala用底层的java.lang.String类来表示字符串。不过,它通过StringOps类给字符串追加了上百种操作。

举例来说,intersect方法输出两个字符串共通的一组字符:

"Hello".intersect("World") // 输出"lo"

在这个表达式中,java.lang.String对象"Hello"被隐式地转换成了一个StringOps对象,接着StringOps类的intersect方法被应用。

因此,在使用Scala文档的时候,记得要看一下StringOps类。

同样地,Scala还提供了RichIntRichDoubleRichChar等。它们分别提供了它们可怜的堂兄弟们——IntDoubleChar等——所不具备的便捷方法。我们前面用到的to方法事实上就是RichInt类中的方法。在表达式

1.to(10)

中,Int1首先被转换成RichInt,然后再应用to方法。

最后,还有BigIntBigDecimal类,用于任意大小(但有穷)的数字。这些类背后分别对应的是java.math.BigIntegerjava.math.BigDecimal,不过,在1.4节你会看到,它们用起来更加方便,你可以用常规的数学操作符来操作它们。

说明:在Scala中,我们用方法,而不是强制类型转换,来做数值类型之间的转换。举例来说,99.44.toInt得到9999.toChar得到'c'。当然,和Java一样,toString将任意的对象转换成字符串。

要将包含了数字的字符串转换成数值,使用toInttoDouble。例如,"99.44".toDouble得到99.44

 

Scala入门指南_编程语言

本文节选自《快学Scala

电子工业出版社出版

(美)霍斯曼(Horstmann,C.S.)著

高宇翔译