第二章 控制结构和函数

条件表达式

scala的if/esle语法结构与Java一样,但是在scala中if/else表达式有值,这个值就是跟在if或else之后表达式的值。

我们可以将if/else表达式的值赋予给变量:

val s = if (x>0) 1 else -1

它等价于

if (x>0) s = 1 else s = -1

不过,第一种写法更好,因为它可以用来初始化一个val, 而第二种写法中,s必须是var。

在Scala中,每个表达式都有一个类型。

如果是混合类型,则类型为Any。

如果else部分缺失,例如:

if (x>0) 1

等价于

if (x>0) else ()

Scala没有switch语句==,但是它有一个更强大的模式匹配机制。

语句终止

在scala中,分号绝大多数情况下都不是必须的。不过如果你想在单行中写下多个语句,则需要将它们以分号隔开。

块表达式和赋值

在Scala中,{}包含一系列表达式,块中最后一个表达式的值就是块的值。

在Scala中赋值语句是没有值的,所以别把它们串接在一起。

x = y = 1 //别这样做

输入和输出

使用print或者println打印一个值。

使用printf格式化输出。

使用readLine从控制台读取一行输入,如果是读取数字,Boolean或者字符串,可以使用readInt, readDouble, readByte, readShort, readLong, readFloat, readBoolean或者 readChar。与其他方法不同,readLine带一个参数作为提示字符串。

循环

scala支持while循环和for循环,while循环与Java的while一样,for循环语法如下:

for( i <- 表达式)

遍历字符串和数组时,你通常需要使用0 到n-1的区间,这个时候可以使用until方法而不是to方法。until方法返回一个并不包含上限的区间。

高级for循环和for推导式

可以使用变量 <- 表达式的形式提供多个生成器,用分号隔开。例如:

for(i <-1 to 3, j <- 1 to 3) print ((10*i+j)+ " ")

每个生成器还可以带过滤条件,以if开头的Boolean表达式。

for(i <-1 to 3, j <- 1 to 3 if i != j) print ((10*i+j)+ " ")

还可以使用任意多的定义,引入可以在循环中使用的变量:

for( i <- 1 to 3; from = 4-i; j <- from to 3)  print ((10*i+j)+ " ")

如果for循环的循环体以yield开始,则该循环会构造出一个集合,每次迭代出集合中的一个值:

for( i <- 1 to 10) yield i % 3

这类循环叫做for推导式。

函数

要定义函数,需要给出函数的名称、参数和函数体:

def abs(x:Double) = if (x>0) x else -x

必须给出所有参数的类型,不过,只要函数不是递归的,就不需要指定返回类型。Scala编译器可以通过=右侧的表达式推断出返回类型。

如果函数体需要多个表达式完成,可以使用代码块,块中最后一个表达式的值就是函数的返回值。

对于递归函数,必须指定返回类型。

默认参数和带名参数

scala中可以给函数提供默认参数:

def func(num:Int = 2) num += 3

还可以在提供参数值的时候指定参数名。带名参数不需要跟参数列表的顺序完全一致。

变长参数

scala中还支持接收可变长度参数列表:

def sum(args: Int*){
var result = 0
for(arg <- args)
        result += arg
result
}

函数得到的是一个类型为Seq的参数。

如果你已经有一个值的序列,则不能直接将它传进上述函数。例如:

val s = sum(1 to 5) //错误

如果sum函数被调用时传入的是单个参数,那么该参数必须是单个整数,而不是一个整数区间。解决这个问题的办法是告诉编译器你希望这个参数被当作参数序列来处理,追加:_*。例如:

val s = sum(1 to 5: _*)

过程

scala中不返回值的函数有特殊的表示法,如果函数体包含在花括号当中,但没有前面的=号,那么返回类型就是Unit。这样的函数称之为过程。

由于过程不返回值,所以我们省略=号。

懒值

当val被声明为lazy时,它的初始化将被推迟,直到我们首次对它赋值。

lazy val words = scala.io.Source.fromFile("a.txt").mkString

如果程序从不访问a.txt,那么它就不会被打开。 懒值对于初始化开销较大的初始化语句而言十分有用。

异常

scala异常工作机制与Java一样,但是scala没有受检异常。

throw有特殊的类型值Nothing,这在if/else语句中特别有用,如果一个分支的类型是Nothing,那么if/else表达式的类型就是另一个分支的类型。

捕获异常的语法采用模式匹配的语法,更通用的异常应该排在更具体的异常后面。

如果不需要使用捕获的异常名,可以使用_代替变量名。