心猿意码Scala之入门

by:leotse

为什么是Scala

有人问Java之父James Gosling“除了Java语言以外,您现在还使用JVM平台上的哪种编程语言?”,他毫不犹豫的回答“Scala”。

During a meeting in the Community Corner (java.net booth) with James Gosling, a participant asked an interesting question:”Which Programming Language would you use now on top of JVM, except Java?”. The answer was surprisingly fast and very clear: - Scala.

可见,Scala是一门很受待见的编程语言,另一位大牛Horstmann指出,Scala试图将以下三组对立的思想融合在一门编程语言中:

函数式编程 VS 面向对象编程
富有表达力的语法 VS 静态类型
高级的语言特性 VS 与Java高度集成

这样看来,Scala就是想集各家所长,打造一种平衡的和谐,这看起来像是编程语言世界的乌邦托。

Scala和很多在Java基础上发展的语言一样,需要基于JVM,这一点使得Scala拥有强大的Java所拥有的特性,比如跨平台。但是成也JVM,败也JVM,JVM启动较慢的问题,需要编译等等这些也成为了Scala的瓶颈。只要还立足于JVM,Scala就一直会受到JVM的限制。
但是这些都无碍于Scala本身成为一门成功的语言,现在很多公司都已经逐渐投靠Scala阵营,比如twitter,特别是当使用Scala编写的Spark兴起之后,Scala更是成为很多公司大数据编程语言的首选。

REPL

首先,我们需要认识一下REPL,全称为Read-Eval-Print-Loop,亦即读取-求值-打印-循环。如果是第一次接触这个概念,会觉得有点奇怪,我们可以将REPL称为交互式解释器。一般的,我们通过REPL可以快速学习和验证一门语言的特性(前提是这门语言支持REPL)。
但是并不是所有的语言都支持REPL,常见的编程语言支持REPL的有Ruby、Python、Lua,使用很广的Java、C++、C#、PHP以及JS等并不支持原生的REPL。当然,我们既然在这里讨论REPL,Scala是肯定支持REPL的。我们在学习Scala的时候可以直接在REPL coding。实际上,我们敲进去的代码首先被编译,然后JVM会执行编译后的字节码,然后返回执行的结果。

我们看一个示例:

1
2
scala> "Hello, Scala"
res0: String = Hello, Scala

从这个示例中,我们可以看到输入的是文本“Hello, Scala”,下面一行是输出,这里的res0是REPL为这个文本起的名字,后面的String表明这个文本是字符串类型。我们可以直接使用res0这个变量名去调用这个字符串文本。

val和var

在上一小节里面,我们已经见识到了Scala的变量声明,但是,我们一般情况下都希望将变量命名的权力牢牢控制在自己手上,因此我们可以使用以下方式声明变量。
var:variable的缩写。用法如下:
var variable_name: [variable_type] = variable_value
变量的类型是可选的,因为如果没有指定变量的类型,Scala的编译器会根据变量的值推断出它的类型。我们看下面的示例:

1
2
3
4
5
6
7
8
scala> var x: Int = 1  // 指定x的类型为Int
x: Int = 1

scala> x = 2 // 改变变量x的值
x: Int = 2

scala> var y = 3 // 没有指定y的类型
y: Int = 3

val:这里说变量其实不太准确,因为val声明的是不可变的常量。使用方法和var类似,只是不能修改它的值。在实际开发中,除非我们可以预知需要改变一个值的内容,否则我们一般用val声明。示例如下:

1
2
3
4
5
scala> val z = 3
z: Int = 3

scala> z = 2 // 不可以修改一个常量的值
<console>:11: error: reassignment to val

一般的,我们不需要声明类型,除非必须。而且我们注意到Scala和Java等语言不一样,变量的类型声明在变量名后面。

我这里引用一段前辈说过的话,里面说明了使用val以及var的场景以及原因:

Scala 编程人员通常应该首选 val 结构,并在明确需要可变性的时候选择 var。原因很简单:除了使编程更容易之外,val 还能确保程序的线程安全性,Scala 中的一个内在主题是:几乎每次认为需要可变状态时,其实都不需要可变状态。 让我们从不可变字段和本地变量(val)开始,这是展示上述情况的一种方法,甚至对最坚定的 Java 怀疑论者也是如此。从 Java 中的 final 开始介绍可能不是很合理,或许是因为 Java 的非函数特性,尽管此原因不可取。一些好奇的 Java 开发人员可能想尝试一下。

另外,我们在REPL中的示例中可以看到,解释器为我们没有命名的变量定义res0这个名字,凡是解释器定义的变量,如res0、res1等等,都是常量,不可修改:

1
2
3
4
5
scala> res0
res1: String = Hello, Scala

scala> res0 = 1990
<console>:11: error: reassignment to val

在Scala中,有8种类型,它们分别为Boolean、Byte、Char、Short、Int、Long、Float以及Double。在这里,我们和Java那样称它们为八大基本类型,因为Scala中并不会刻意去区分基本类型和引用类型,因为他们都是类。