Scala 控制结构和函数

0.要点

  • if 表达式有值
  • 块也有值,是它最后一个表达式的值
  • 分号(在绝大多数情况下)不是必需的
  • void类型是Unit
  • 避免在函数定义中使用return
  • 注意别在函数定义式中漏掉了 =
  • 异常的工作方式和Java或C++中基本一样,不同的是你在catch语句中使用“模式匹配”。
  • Scala没有受检异常

1.条件表达式

if (x > 0) 1 else -1
val s = if(x > 0) 1 else -1 
相当于 Java 或 C++:s = x > 0 ? 1 : -1

表达式if(x>0) 1 else -1的类型为Int,因为2个分支的类型都是Int;
if(x>0) "positive" else -1的类型为2个分支类型的公共超类型。本例中,其中一个类型是java.lang.String,另一个类型是Int,它们的公共超类型叫做Any。
else 部分缺失:if ( x > 0 ) 1
在Scala中,每个表达式都应该有某种值。这个问题的解决方案是引入一个Unit类,写做()。
if(x > 0) 1 等同于 if(x > 0) 1 else ()
()是表示“空值”的占位符,将Unit当做Java或C++中的void。

3.块表达式和赋值

{ }块包含一系列表达式,其结果也是一个表达式。块中最后一个表达式的值就是块的值。

val distance = {
val dx = x-x0;
val dy = y - y0;
sqrt(dx * dx + dy * dy)
 }

在Scala中,赋值动作本身是没有值的——它的值是Unit类型,赋值语句结束的块,如:

{
 r = r * n;
 n -= 1
}

它的值是Unit类型。

x = y =1 # 不能这样
y = 1的值是(),所以x=()
在Java和C++中,赋值语句的值是被赋的那个值,所以可以将赋值语句串接在一起。
5.循环
while(n > 0){
    r = r * n
    n -= 1
}
for(i <- 1 to n)
    r = r * i

val s = "Hello"
var sum = 0
for(i <- 0 until s.length) //i的最后一个取值是s.length-1
    sum += s(i)

var sum = 0
for(ch <- "Hello") sum +=ch

中途退出循环:
1. 使用Boolean型的控制变量
2. 使用嵌套函数——从函数中return
3. 使用Breaks对象中的break方法

6.高级for循环和for推导式

for(i <- 1 to 3;j<- -1 to 3) print ((10 * i + j) + " ")
// 11 12 13 21 22 23 31 32 33
for(i <- 1 to 3;j<- 1 to 3 if i != j){
print ((10*i +j) + " ")
} 
//12 13 21 23 31 32 //if前没有分号
for(i <- 1 to 3;from = 4 - i;j <- from to 3){
    print((10 * i + j) + " ")
}
// 13 22 23 31 32 33

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

for(i <- 1 to 10) yield i % 3
//生成Vector(1,2,0,1,2,0,1,2,0,1)

for推导式生成的集合与它的第一个生成器是类型兼容的。
for(c <- "Hello";i <- 0 to 1) yield (c+i).toChar
// "HIeflmlmop"
for(c <- 0 to 1;c <- "Hello") yield (c+i).toChar
//Vector('H','e','l','l','o','I','f','m','m','p')

7.函数

定义函数:要给出函数名,输入参数,返回值类型,函数体
返回类型当函数是递归时指出。
Scala编译器可以通过=符号右侧的表达式的类型推断出返回类型。

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

def fac(n:Int) = {
var r =1 
for (i <- 1 to n) r = r * i
r
}

//递归
def fac(n:Int):Int = if(n <= 0) 1 else n * fac(n-1)
//如果没有返回类型,Scala编译器无法校验n*fac(n-1)的类型是Int。

8.默认参数和带名参数

def decorate(str:String, left:String="[", right:String = "]") = left + str + right

参数left和right带有默认值”[“和”]”

decorate("Hello")  => "[Hello]"
decorate("Hello","<<<",">>>")=>"<<<Hello>>>"

9.变长参数

def sum(args:Int*)={
    var result = 0
    for (arg <- args) result += arg
    result
}
val s = sum(1,4,9,16,25)
//函数得到的是一个类型为Seq的参数,可以用for循环来访问每一个元素。
val s = sum(1 to 5) //错误
val s = sum(1 to 5:_*)//将1 to 5当做参数序列处理

递归定义中:

def recursiveSum(args:Int*):Int = {
    if (args.length == 0) 0
    else args.head+recursiveSum(args.tail:_*)
}
序列的head是它的首个元素,tail是所有其他元素的集合序列,这也是个Seq,用_*将它转换成参数序列。

10.过程

如果函数体包含在{ }中,但没有前面的=号,那么返回类型就是Unit。这样的函数称为过程(procedure)

def box(s:String){//没有等号
var border = "-" * s.length + "--\n"
println(border + "|" + s + "|\n" + border)
}

也可以显式定义Unit返回类型:

def box (s:String):Unit = {
...
}

11.懒值

首次对它取值时才初始化

lazy val words = scala.io.Source.fromFile(“/usr/share/dict/words”).mkString

12.异常

throw new IllegalArgumentException(“x should not be negative”)
throw表达式有特殊的类型Nothing。这在if/else中很有用。如果一个分支的类型是Nothing,那么if/else表达式的类型就是另一个分支的类型。
如:

if( x >= 0){
    sqrt(x)
}else throw new IllegalArgumentException("x should not be negative")
//第一个分支的类型是Double,第二个分支的类型是Nothing,因此,if/else表达式的类型是Double。

捕获异常的语法采用的是模式匹配的语法:

try{
    process(new URL("http://horstmann.com/fred-tiny.gif"))
}catch{
    case _: MalformedURLException => println("Bad URL:" + url)
    case ex:IOException => ex.printStackTrace()
}

更通用的异常应该在更具体的异常之后。
try/catch语句处理异常,try/finally语句在异常没有被处理时执行某种动作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值