第二章 控制结构和函数

条件表达式

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

我们可以将 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 <- 表达式)

遍历字符串和数组时,你通常需要使用 0n-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 表达式的类型就是另一个分支的类型。

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

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