由于课程的需要,要开始学习Scala了。感觉最近的线程开得有点多啊,争取能做到平衡发展吧。
本章的主题是“基础”,主要介绍一系列重要的Scala概念和惯用法。同时还会学到如何浏览Scaladoc文档。
要点包括:
- 使用Scala解释器
- 用var和val定义变量
- 数字类型
- 使用操作符和函数
- 浏览Scaladoc
配置Scala环境
我选用了Intellij IDEA作为IDE。下载链接:https://download.jetbrains.8686c.com/idea/ideaIC-2017.1.exe。
对应的Scala版本是2.11.8,主要是因为我的JDK是1.7版本的。Scala的下载地址是http://downloads.lightbend.com/scala/2.11.8/scala-2.11.8.msi
Scala解释器
在命令行里面使用下面的命令来启动Scala解释器:
scala
然后输入下面的命令:
scala> 8 * 5 + 2
res3: Int = 42
答案被命名为res3,在后面的操作中可以继续使用它。
scala> 0.5 * res3
res4: Double = 21.0
scala> "Hello," + res3
res5: String = Hello,42
下面来体验一下自动补全,如果输入res5.to
后按下Tab键,如果出现下面的提示:
to toBuffer toDouble toInt toList toMap toShort toTraversable
toArray toByte toFloat toIterable toLong toSeq toStream toUpperCase
toBoolean toCharArray toIndexedSeq toIterator toLowerCase toSet toString toVector
说明自动补全是好的。
Scala解释器读到一个表达式,对它进行求值,将它打印出来,接着再继续读下一个表达式。这个过程被称作读取-求值-打印-循环,即REPL。
从技术上将,scala程序并不是一个解释器。实际发生的是,你输入的内容被快速地编译成字节码,然后这段字节码交由Java虚拟机执行。正因如此,大多数Scala程序员更倾向于将它称作“REPL”。
之前面试的时候面试官问我Scala和Java有什么联系,我并不太清楚。现在给出一个猜测性的答案:Scala和Java都运行在JVM上,所以Scala应该能调用Java的类库来为自己服务。
声明值和变量
除了直接使用res0、res1这些名称之外,也可以定义自己的名称:
scala> val answer = 8 * 5 + 2
answer: Int = 42
可以在后续表达式中使用这些名称。
scala> 0.5 * answer
res7: Double = 21.0
但是不能改变它的值。
scala> answer = 0
<console>:12: error: reassignment to val
answer = 0
可以使用下面的代码来声明一个可变的变量:
var counter = 0
counter = 1
在Scala中,我们鼓励你使用val-除非你真的需要改变它的内容。
你不需要给出值或者变量的类型,这个信息可以从你用来初始化它的表达式推断出来。(声明值或变量但不做初始化会报错)。
在必要的时候,你也可以指定类型。例如:
scala> val greeting: String = null
greeting: String = null
scala> val greeting: Any = "Hello"
greeting: Any = Hello
在Scala中,变量或函数的类型总是写在变量或函数名称的后面。这使得我们更容易阅读哪些复杂类型的声明。
在Scala中,晋档同一行代码中存在多条语句是才需要用分号隔开。
可以将多个值或者变量放在一起声明:
scala> val xmax,ymax = 100
xmax: Int = 100
ymax: Int = 100
scala> var greeting,message: String = null
greeting: String = null
message: String = null
常用类型
Scala有7中数值类型:Byte,Char,Short,Int,Long,Float和Double,以及一个Boolean类型。与Java不同,这些类型是类。Scala并不刻意区分基本类型和引用类型。可以对数字执行方法,例如:
scala> 1.toString()
res8: String = 1
还有更有意思的:
scala> 1.to(10)
res9: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
在Scala中,我们不需要包装类型。在基本类型和包装类型之间的转换是Scala编译器的工作。
Scala用底层的java.lang.String类来表示字符串。不过它通过StringOps类给字符串追加了上百种操作。举个例子:
scala> "Hello".intersect("World")
res10: String = lo
待会儿在使用Scala文档的时候记得看一下StringOps类。
同样地,Scala还提供了RichInt、RichDouble、RichChar等。它们提供了很多便捷的方法。在表达式
1.to()
中,Int值1首先被转换成RichInt,然后再应用to方法。
Scala还提供了BigInt和BigDecimal类。
在Scala中,用方法而不是强制类型转换来做数值类型之间的转换。比如:
scala> 99.44.toInt
res12: Int = 99
scala> 99.44.toChar
res13: Char = c
scala> 99.44.toString
res14: String = 99.44
算数和操作符重载
Scala的算数操作符和在Java和C++中预期的效果是一样的。
a + b 实际上是a.+b的简写
在Scala中你可以使用几乎任何符号来为方法命名。
Scala并没有提供++和–操作符,我们需要使用+=1或者-=1
counter += 1
对于BigInt和BigDecimal对象,你可以用常规的方式使用数学操作符:
scala> val x : BigInt = 1234567890
x: BigInt = 1234567890
scala> x * x * x
res16: scala.math.BigInt = 1881676371789154860897069000
Scala允许你定义操作符,由你来决定是否要在必要的时候有分寸的使用这个特性。
调用函数和方法
在Scala中使用数学函数更为简单。
scala> import scala.math._ // _字符是通配符
import scala.math._
scala> sqrt(2)
res19: Double = 1.4142135623730951
scala> pow(2,4)
res20: Double = 16.0
scala> Pi
res21: Double = 3.141592653589793
scala> min(3,Pi)
res22: Double = 3.0
Scala没有静态方法,不过它有个类似的特性,叫做单例对象。通常一个类对应有一个伴生对象,其方法就跟Java中的静态方法一样。
不带参数的Scala方法通常不使用圆括号。
scala> "Hello".distinct
res23: String = Helo
一般来说,没有参数且不改变当前对象的方法不带圆括号。
apply方法
使用s(i)来取出字符串的第i个字符。
scala> "Hello"(4)
res24: Char = o
可以把这种用法当做是()操作符的重载形式,背后的实现原理是一个名为apply的方法。”Hello”(4)是如下语句的简写:
"Hello".apply(4)
对于BigInt来说,
BigInt("1234567890")
是
BigInt.apply(“1234567890”)
的简写,用于生产一个新的BigInt对象。
这样使用伴生对象的apply方法是Scala中构建对象的常用手法。例如,Array(1,4,9,16)返回一个数组,用的就是Array伴生对象的apply方法。
scala> Array(1,4,9,16)
res25: Array[Int] = Array(1, 4, 9, 16)