目录
Scala的控制结构与函数
控制结构
scala和其他编程语言之间一个根本性的差异。在Java或C++中, 我们把表达式(比如3 + 4)和语句(比如if语句)看做两样不同的东西。表达式有值,表达式有值,而语句执行动作。在Scala中,几乎所有构造出来的语法结构都有值。这个特性使得程序更加精简,也更易读。
-
if表达式有值。
-
块也有值——是它最后-一个表达式的值。
-
Scala的for循环就像是 “增强版”的Java for循环。
-
分号(在绝大多数情况下)不是必需的。
-
void类型是Unit。
-
避免在函数定义中使用return。
-
注意别在函数式定义中漏掉了=。
-
异常的工作方式和Java或C++中基本一 样,不同的是你在catch语句中使用“模式匹配”。
-
Scala没有受 检异常。
条件表达式
Scala的if/else语法结构和Java或C++一样。不过,在Scala中if/else表达式有值, 这个值就是跟在if或else之后的表达式的值。
例如:
在Scala中,每个表达式都有一一个类型。举例来说,表达式if(x> 0) 1 else -1的类型是Int,因为两个分支的类型都是Int。
混合类型表达式,比如:
上述表达式的类型是两个分支类型的公共超类型。在本例中,其中一个分支是java.lang.String,而另-一个分支是Int。 它们的公共超类型叫做Any。有时候,如果只有if没有else语句,比如if(x> 0) 1,那么有可能if语句没有输出值。但是在Scala中,每个表达式都应该有某种值。这个问题的解决方案是引入一个Unit类,写做()。不带else的这个if语句等同于if(x> 0) 1 else ()。
可以把()当做是表示“无有用值"的占位符,将Unit当做Java或C++中的void。从技术上讲, void没有值但是Unit有一个表示“无值"的值.就好比空的钱包和里面有一张写着“没钱”的无面值钞票的钱包之间的区别。
要注意的是,scala中没有switch语句,但是与之对应的有一个更强大的模式匹配机制。
块表达式和赋值
在Java或C++中,块语句是一个包含于{ }中的语句序列。每当你需要在逻辑分支或循环中放置多个动作时,你都可以使用块语句。在Seala中,{}块包含 一系列表达式,其结果也是一个表达式。块中最后一个表达式的值就是块的值。
例如:
{ }块的值取其最后一个表达式。变量x和y仅作为计算所需要的中间值,很干净地对程序其他部分而言不可见了。在Scala中,赋值动作本身是没有值的一或者, 更严格地说,它们的值是Uni类型的。Unit类型等同于Java和IC++中的void,而这个类型只有一个值,写做()。
输入和输出
如果要打印一个值,用print或println函数。 后者在打印完内容后会追加一个换行符:
用readLine函数从控制台读取一行输入。 如果要读取数字、Boolean或者是字符,可以用readInt、readDouble、readByte、 readShort、readLong、 readFloat 、readBoolean或者readChar。与其他方法不同,readLine带一个参数作为提示字符串:
循环
scala有与java和c++一样的while和do循环。但对于for循环,则稍微有点不一样。scala中for语句的语法结构为:
for(i <- 表达式)
除了to关键字,也可以使用until关键字,前者双端闭区间,后者左开右闭。
需要注意的是:Scala并 没有提供break或continue语句来退出循环。如果需要break,我们可以:
-
使用Boolean型的控制变量。
-
使用嵌套函数,可以从函数当中return。
-
使用Breaks对象中的break方法。
除此之外,for()中可以包括对个生成器,每个生成器都可以带一个守卫,用分号隔开:
这个代码块的功能可以类比java和c++中的二层循环,i由1到3是第一层,j是第二层。
如果for循环的循环体以yield开始,则该循环会构造出-一个集合,每次迭代生成集合中的一一个值:
函数
Scala除了方法外还支持函数。方法对对象进行操作,函数不是。
函数的定义
要定义函数,需要给出函数的名称、参数和函数体,就像这样:
def abs (x: Double) = if (x >=0) x else -X
你必须给出所有参数的类型。不过,只要函数不是递归的,你就不需要指定返回类型。Scala编译器可以通过=符号右侧的表达式的类型推断出返回类型。如果函数体需要多个表达式完成,可以用代码块。块中最后一个表达式的值就是函数的返回值。
比如:
对于递归函数,我们必须指定返回类型。例如:
如果没有返回类型,Scala编译器无法校验n * fac(n - 1)的类型是Int。
默认参数和带名参数
我们在调用某些函数时可以并不显式地给出所有参数值,对于这些函数我们可以使用默认参数。例如:
当然也可以传入自己的参数,使用带名参数:
带名参数可以让函数更加可读。它们对于那些有很多默认参数的函数来说也很有用。也可以混用未命名参数和带名参数,只要那些未命名的参数是排在前面的即可:
变长参数
有时候,实现一个可以接受可变长度参数列表的函数会更方便。
比如:
如果你已经有一个值的序列,则不能直接将它传入上述函数。举例来说,如下的写法是不对的:
如果sum函数被调用时传入的是单个参数,那么该参数必须是单个整数,而不是一个整数区间。解决这个问题的办法是告诉编译器你希望这个参数被当做参数序列处理。追加:_*,就像这样:
过程
Scala对于不返回值的函数有特殊的表示法。如果函数体包含在花括号当中但没有前面的=号,那么返回类型就是Unit。这样的函数被称做过程( procedure)。过程不返回值,我们调用它仅仅是为了它的副作用。举例来说,如下过程把一个字符串打印在一个框中,就像这样: