表达式
表达式是返回一个值的代码单元,表达式的关键就是要返回捕获和使用的值。
之前我们定义值和变量是都赋为字面量值,更准确的说法是将他们赋为表达式的返回值,而不论表达式是字面量、计算式还是函数调用。
表达式块
可以使用大括号结合多个表达式创建一个表达式块,表达式有自己的作用域,可以包含表达式块中的局部值和变量。
块中的最后一个表达式将作为整个表达式块的返回值
表达式块也可以嵌套,每一级表达式块都有自己的值和变量。
{
val a = 1;
{
val b = a * 2;
{
val c = b + 4;
c
}
}
}
if表达式
可以根据一个表达式的解析结果(true或false)选择一个代码分支。
使用if块作为表达式的问题在于:它们只能有条件地返回一个值。如果布尔表达式返回false,你认为if块会返回什么?
举例:val result = if(false) "what does this return?“
——这个例子中结果值的类型未指定,可能会返回一个String或Unit,所以编译器会选择根类Any。这是String(扩展了AnyRef)和Unit(扩展了AnyVal)共同的根类。
if...else表达式
举例:
val x = 10;
val y = 20
val max = if(x>y) x else y
如果if...else表达式不能很容易地放在一行上,就应该考虑使用表达式块,这样代码会更可读。
匹配表达式match
类似C和Java的“Switch”语句,首先会计算一个输入项,并执行第一个“匹配”模式,然后返回它的值。
举例:上面的例子,不同的实现方式
val x = 10;
val y = 20
val max = x > y match{
case true => x
case false => y
}
一个case块中的语句和表达式个数没有任何限制,只是最后一个表达式会用作匹配表达式的返回值。
val status = 500
val message = status match {
case 200 => "OK"
case 404 => {
println("ERROR - we called the service incorrectly")
"error"
}
case 500 => {
println("ERROR - the service encountered an error")
"error"
}
}
多个模式重用相同的case块,可以使用模式替换避免重复的代码。
val day = "MON"
val kind = day match{
case "MON"|"TUE"|"WED"|"THU"|"FRI" => "weekday"
case "SAT"|"SUN" => "weekend "
}
如果找不到与数据表达式匹配的模式,会发生什么?
例如:"match me" match {case "match" => "sorry"} ——会报scala.MatchError错误
为了避免错误破坏匹配表达式,可以使用一个通配的“全匹配”模式。将通配模式作为最后一个模式放在匹配表达式中,这会匹配所有可能
得输入模式,从而避免scala.MatchError。
全匹配的两种办法:
①值绑定:利用值绑定或变量绑定,将把匹配表达式的输入绑定到一个局部值,然后可以在case块的体中使用。由于模式包含所绑定的值名,并没有要匹配的具体模式,因此值绑定是一个通配模式,他能匹配任何输入值。
val message = "OK"
val status = message match{
case "OK" => 200
case other => {
println(s"Count't parse $other")
-1
}
}
②通配符:通配符是一个下划线(_)字符,相当于一个匿名占位符,最后将在运行时替换为一个表达式的值。与值绑定类似,下划线通配符没有提供可以匹配的具体模式,因此这是一个通配模式,也可以匹配任何输入值。
val message = "Unauthorized"
val status = message match{
case "OK" => 200
case _ => {
println(s"Count't parse $message")
-1
}
}
匹配表达式+if表达式
val response:String = null
response match{
case s if s !=null => println(s"Received '$s'")
case s => println("Error! Receive a null response")
}
语句
语句就是不返回值的表达式。
语句的返回类型为Unit,这种类型指示没有值。
循环控制语句
for循环
在Java中循环经常会用到数值递增/递减,例如for(int i = 0, i < 10, i++)
而scala中语法结构为for(临时变量 <- 迭代对象)
举例:
for (i <- 1 to 10) //从1到10增序
for (i <- 1 to 10 reverse) //从10到1降序
for (i <- Range(1,10)) //从1到9(不包括10),默认步长为1,增序
for (i <- Range(10,1,-1)) //从10到2(不包括1),降序
yield关键字
如果表达式中指定了yield这个关键字,调用的所有表达式的返回值将作为一个集合返回。
val days = for (x <- 1 to 7) yield {
x
}
println(days)
for (x <- days){
println(x)
}
还可以为迭代器增加一个if表达式。使用迭代器哨卫时,可以跳过一次迭代,除非if表达式返回true。
val threes = for(i <- 1 to 20 if i%3 ==0) yield {
"h"+i
}
for (j <- threes){
println(j)
}
==========================================================================================================================
val strs = "Faith,Hope,,Charity"
for{
t <- strs.split(",")
if t != null
if t.size>0
}
{
println(t)
}
嵌套迭代器(就是多重for循环啦
①原来的方式
for(x <- Range(1,3)){
for(y <- Range(2,4)){
println(s"$x,$y")
}
}
②使用嵌套迭代器
for{x <- Range(1,3);y <- Range(2,4)}
{
println(s"$x,$y")
}
如果for循环使用小括号,最后一个迭代器之前的各个迭代器行必须以一个分号结尾。
对于使用大括号的for循环,迭代器行末尾的分号则是可选的,在同一行时需要使用分号分割。
while循环和do-while循环
二者语法同Java完全相同,这里就不再赘述