条件表达式
Scala的if/else语法结构和Java或C++一样。不过,在Scala中if/else表达式有值,这些值就是跟在if或者else之后的表达式的值。如:if (x >0) 1 else -1,此表达式的值是1或者-1。
scala> var x = 1
x: Int = 1
scala> val s = if(x>0) 1 else -1
s: Int = 1
注:val-定义不可变变量,var-定义可变变量。if/else表达式的值可赋值给变量。
在Scala中,每个表达式都有一个类型。如上例if(x>0) 1 else -1的类型为Int,因为两个分支的类型都是Int。如果为混合型的表达
式,则类型是两个分支类型的公共超类型Any。
scala> var x = 1
x: Int = 1
scala> val res = if(x>0) "postive" else -1
res: Any = postive
在Scala中,每个表达式都应该有某种值,如果if分支缺失else部分,如if(x>0) 1,当x<0时,则返回()。
scala> var x = -1
scala> val res = if(x>0) 1 x: Int = -1
res: AnyVal = ()
注:在这种情况下,Scala引入了Unit类,写做()。不带else的这个if语句等同于if(x>0) 1 else ()。你可以把()当做是表示“无有用值”的占位符,将Unit当做在Java或C++中的void。从技术上讲,void没有值但是Unit有一个表示“无值”的值。
语句终止
在Java和C++中,每个语句都以分号结束。而在Scala中-与JavaScript和其它脚本语言类似-行尾的位置不需要分号。
同样,在}、else以及类似的位置也不必写分号,只要能够从上下文明确的判断出这里是语句的终止即可。
语句终止注意点:
1.在单行中写下多个语句,需要将语句以分号分开,最后一条语句可不写分号。
2.如果语句较长需分多行来写,需确保第一行以一个不能用做语句结尾的符号结尾。
块表达式和赋值
scala> val res = {val res1 = 6 - 5; val res2 = 3 + 2; res1 + res2}
res: Int = 6
注:{}块的值取决于最后一个表达式。
输入与输出
循环
Scala拥有与Java和C++相同的while和都循环。例如,
scala> var x = 100;
x: Int = 100
scala> var res = 0;
res: Int = 0
scala> while(x>=0) {res = res + x; x = x - 1;}
scala> print(res)
5050
scala> var x = 100;
x: Int = 100
scala> var res = 0;
res: Int = 0
scala> do{res = res + x;x = x -1;}while(x>0)
scala> print(res)
5050
scala> var x = 100;
x: Int = 100
scala> var res = 0;
res: Int = 0
scala> for(i <- 1 to x) res = res + i;
scala> println(res)
5050
注:for循环的语句结构为-for(i <- 表达式),即让变量i遍历<-右边的表达式的所有值。在此for循环中,变量i并没有进行val或var的指定,该变量的类型是集合的元素类型,循环变量的作用域一直持续到循环结束。
在Scala中,没有提供break或continue语句来退出循环。那么如果需要break时,你可以用以下方式去实现:
1.使用Boolean型的控制变量。
2.使用嵌套函数-你可以从函数当中return。
3.使用Breaks对象中的break方法;
import scala.util.control.Breaks._
breakable{
for(...){
if(...) break;//退出breakable块
}
}
注:此代码,控制权的转移是通过抛出和捕获异常完成的,因此,如果时间很重要的话,应尽量避免使用这套机制。
高级for循环和for推导式
在Scala中,你可以以变量 <-表达式的形式提供多个生成器,用分号将它们隔开,如:scala> for(i <- 1 to 3; j <- 1 to 3) print((10 * i + j) + " ")
11 12 13 21 22 23 31 32 33
每个生成器可以带一个守卫,以if开头的Boolean表达式,如:
scala> for(i <- 1 to 3; j <- 1 to 3 if i != j) print((10 * i + j) + " ")
12 13 21 23 31 32
注:if之前没有分号。
你可以使用任意多的定义,引入可以在循环中使用的变量,如
scala> for(i <- 1 to 3; from = 4 - i; j <- from to 3) print((10 * i + j) + " ")
13 22 23 31 32 33
在Scala中,如果循环体以yield开始,则该循环会构造出一个集合,每次迭代生成集合中的一个值,如:
scala> for(c <- "Hello"; i <- 0 to 1) yield (c + i).toChar
res7: String = HIeflmlmop
注:for推导式生成的集合与它第一个生成器是类型兼容的。
函数
Scala除了支持方法外还支持函数。方法对对象进行操作,函数不是。要定义函数,你需要给出函数名、参数和函数体,如以下结构def abs(x: Double) = if(x > 0) x else -xdef fac(n: Int) = {
var r = 0;
for(i <- 1 to n) r = r + i;
r
}
注:在cmd命令行执行时,因REPlL(读取-求值-打印-循环)只能看到一行代码,所以在执行以上代码是可用粘贴模式,键入:paste即可,把代码粘贴进去,然后按下Ctrl+D。这样REPL就会把代码块当做一个整体分析。
def fac(n: Int): Int = if(n<0) 1 else n * fac(n-1)
注:如果没有返回值,Scala编译器无法校验n * fac(n-1)的类型是Int。
默认参数和带名参数
在Scala中,调用某些函数时可以不显式地给出所有参数值,对于这些函数我们可以使用默认参数。如:
def decorate(str: String, left: String = "[", right: String = "]") = left + str + right
注:left和right的默认参数分别为[和]。
调用方式:
1.使用decorate("Hello"),得到[Hello]。
2.使用decorate("Hello", "<<<", ">>>"),得到<<<Helo>>>。
3.提供参数值的时候指定参数名,即使用decorate(left = "<<<", str = "Hello", right = ">>>"),得到<<<Hello>>>。注:带名参数不需要跟参数列表的顺序保持一致。
4.混用未命名参数和带名参数,即decorate("Hello", right = "]>>>"),得到[Hello]>>>。注:未命名参数要排在前面。
变长参数
Scala函数可以接受可变长度参数列表,如:
scala> :paste
// Entering paste mode (ctrl-D to finish)
def sum(args: Int*) = {
var result = 0;
for(arg <- args) result += arg;
result
}
// Exiting paste mode, now interpreting.
sum: (args: Int*)Int
scala> val s = sum(1, 2, 3, 4, 5, 6)
s: Int = 21
注:在复制完函数后,按Enter键后,使用Ctrl+D退出paste模式。在调用函数sum时,sum函数得到的是一个类型为Seq的参数。如果你已经有一个值的序列,则不能直接将它传入sum函数,如sum(1 to 5)是错误的,在调用sum函数之前,你需要告诉编译器你希望这个参数被当做参数序列处理,你可这样调用,在表达式后面追加: _*,即使用sum(1 to 5: _*)调用即可。
过程
在Scala中,对于不返回值的函数有特殊的表示法。如果函数体包含在花括号当中但没有前面的=号,那么返回类型就是Unit。这样的函数被称做过程(procedure)。过程不返回值,我们调用它仅仅是为了它的副作用。
懒值
当val被声明为lazy时,它的初始化将被推迟,直至我们首次对它取值。如,
lazy val words = scala.io.Source.formFile("")
注:formFile参数可为本地路径-可参照scala文件操作API。懒值并不是没有额外开销,我们每次访问懒值,都会有一个方法被调用,而这个方法将会以线程安全的方式检查该值是否已被初始化。
异常
在Scala中,异常的工作机制和Java和C++一样,即当你抛出异常时,当前的运算被中止,运行时系统查找可以接受该异常的异常处理器。控制权将在离抛出点最近的处理器恢复。如果没有找到符合要求的异常处理器,则程序退出。
和Java一样,抛出的对象必须是java.lang.Throwable的子类,但在Scala中throw表达式有特殊类型为Nothing。不过,与Java不同的是,Scala没有"受检"异常-你不需要声明说函数或方法可能会抛出某种异常。
在Scala中,捕获异常的语法采用的是模式匹配的语法,与Java或C++一样,更通用的异常应该排在具体的异常之后。注意,如果你不需要使用捕获的异常对象,可以使用_来替代变量名。try/finally语句让你可以释放资源,不论有没有异常发生。try/catch和try/finally的目的是互补的,try/catch语句处理异常,而try/finally语句在异常没有被处理时执行某种动作。你也可以使用单个的try/catch/finally语句处理异常并释放资源。