scala之控制结构和函数

条件表达式

  Scala的if/else语法结构和Java或C++一样。不过,在Scala中if/else表达式有值,这些值就是跟在if或者else之后的表达式的值。如:if (x  >0) 1 else -1,此表达式的值是1或者-1。

scala> var x = 1
x: Int = 1
scala> val s = if(x>0) 1 else -1
s: Int = 1

注:val-定义不可变变量,var-定义可变变量。if/else表达式的值可赋值给变量。


在Scala中,每个表达式都有一个类型。如上例if(x>0) 1 else -1的类型为Int,因为两个分支的类型都是Int。如果为混合型的表达

式,类型是两个分支类型的公共超类型Any。

scala> var x = 1
x: Int = 1

scala> val res = if(x>0) "postive" else -1
res: Any = postive

  

  在Scala中,每个表达式都应该有某种值,如果if分支缺失else部分,如if(x>0) 1,当x<0时,则返回()。

scala> var x = -1
scala> val res = if(x>0) 1 x: Int = -1

res: AnyVal = ()
注:在这种情况下,Scala引入了Unit类,写做()。不带else的这个if语句等同于if(x>0) 1 else ()。你可以把()当做是表示“无有用值”的占位符,将Unit当做在Java或C++中的void。从技术上讲,void没有值但是Unit有一个表示“无值”的值。

语句终止

在Java和C++中,每个语句都以分号结束。而在Scala中-与JavaScript和其它脚本语言类似-行尾的位置不需要分号。

同样,在}、else以及类似的位置也不必写分号,只要能够从上下文明确的判断出这里是语句的终止即可。

语句终止注意点:

  1.在单行中写下多个语句,需要将语句以分号分开,最后一条语句可不写分号。

  2.如果语句较长需分多行来写,需确保第一行以一个不能用做语句结尾的符号结尾。

块表达式和赋值

在Java和C++中,块语句是一个包含于{}中的语句序列。每当你需要在逻辑分支或循环中放置多个动作时,你都可以使用块语句。 而在
Scala中,{}块 包含一系列表达式,其结果也是一个表达式。块中最后一个表达式的值就是块的值。如
scala> val res = {val res1 = 6 - 5; val res2 = 3 + 2; res1 + res2}
res: Int = 6
注:{}块的值取决于最后一个表达式。

在Scala中,赋值动作本身是没有值的-或者,更严格地说,它们的值是Unit类型的。Unit类型等同于Java和C++中的void,而这个
类型只有一个 值, 写做()。由于赋值语句的值是Unit类的,别把赋值语句串联在一起,如赋值语句y=1的值是()。对于Java和C++,
赋值语句的值是被 赋的那个值, 在这些语言中,将赋值语句串联起来是有意义的。

输入与输出

在Scala中,每个源文件隐含的加入以下引用:
1.import java.lang._
2.import scala._
3.import Predef._
包scala中的Predef对象包含了许多有用的方法-详情可见Scala API。如,通常我们所使用的println、readLine、assert等。

循环

Scala拥有与Java和C++相同的while和都循环。例如,

scala> var x = 100;
x: Int = 100

scala> var res = 0;
res: Int = 0

scala> while(x>=0) {res = res + x; x = x - 1;}

scala> print(res)
5050
scala> var x = 100;
x: Int = 100

scala> var res = 0;
res: Int = 0

scala> do{res = res + x;x = x -1;}while(x>0)

scala> print(res)
5050
  
  在Scala中,没有与for(初始化变量;检查变量是否满足条件;更新变量)循环直接对应的结构,如果你需要使用这样的循环,可使用如下for语句:

scala> var x = 100;
x: Int = 100

scala> var res = 0;
res: Int = 0

scala> for(i <- 1 to x) res = res + i;

scala> println(res)
5050
注:for循环的语句结构为-for(i <- 表达式),即让变量i遍历<-右边的表达式的所有值。在此for循环中,变量i并没有进行val或var的指定,该变量的类型是集合的元素类型,循环变量的作用域一直持续到循环结束。

在Scala中,没有提供break或continue语句来退出循环。那么如果需要break时,你可以用以下方式去实现:

      1.使用Boolean型的控制变量。

      2.使用嵌套函数-你可以从函数当中return。

      3.使用Breaks对象中的break方法;

import scala.util.control.Breaks._
breakable{
    for(...){
      if(...) break;//退出breakable块
    }
}
注:此代码,控制权的转移是通过抛出和捕获异常完成的,因此,如果时间很重要的话,应尽量避免使用这套机制。

高级for循环和for推导式

  在Scala中,你可以以变量 <-表达式的形式提供多个生成器,用分号将它们隔开,如:
scala> for(i <- 1 to 3; j <- 1 to 3) print((10 * i + j) + " ")
11 12 13 21 22 23 31 32 33
  每个生成器可以带一个守卫,以if开头的Boolean表达式,如:
scala> for(i <- 1 to 3; j <- 1 to 3 if i != j) print((10 * i + j) + " ")
12 13 21 23 31 32
注:if之前没有分号。

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

scala> for(i <- 1 to 3; from = 4 - i; j <- from to 3) print((10 * i + j) + " ")
13 22 23 31 32 33
  在Scala中,如果循环体以yield开始,则该循环会构造出一个集合,每次迭代生成集合中的一个值,如:
scala> for(c <- "Hello"; i <- 0 to 1) yield (c + i).toChar
res7: String = HIeflmlmop
注:for推导式生成的集合与它第一个生成器是类型兼容的。

函数

  Scala除了支持方法外还支持函数。方法对对象进行操作,函数不是。要定义函数,你需要给出函数名、参数和函数体,如以下结构def abs(x: Double) = if(x > 0) x else -x
      1.你必须给出所有参数的类型。不过,只要函数不是递归的,你就不需要指定返回类型。Scala编译器可以通过=符号右侧的表达式的类型推断出返回类型。
      2.如果函数体需要多个表达式完成,你可以使用代码块。代码块最后一个表达式的值就是函数的返回值。
  如求前N项的和:
def fac(n: Int) = {
  var r = 0;
  for(i <- 1 to n) r = r + i;
  r
}
注:在cmd命令行执行时,因REPlL(读取-求值-打印-循环)只能看到一行代码,所以在执行以上代码是可用粘贴模式,键入:paste即可,把代码粘贴进去,然后按下Ctrl+D。这样REPL就会把代码块当做一个整体分析。

  对于递归函数,我们必须指定返回类型。如:
def fac(n: Int): Int = if(n<0) 1 else n * fac(n-1)
注:如果没有返回值,Scala编译器无法校验n * fac(n-1)的类型是Int。

默认参数和带名参数

  在Scala中,调用某些函数时可以不显式地给出所有参数值,对于这些函数我们可以使用默认参数。如:

def decorate(str: String, left: String = "[", right: String = "]") = left + str + right
注:left和right的默认参数分别为[和]。

调用方式:

   1.使用decorate("Hello"),得到[Hello]。

   2.使用decorate("Hello", "<<<", ">>>"),得到<<<Helo>>>。

   3.提供参数值的时候指定参数名,即使用decorate(left = "<<<", str = "Hello", right = ">>>"),得到<<<Hello>>>。注:带名参数不需要跟参数列表的顺序保持一致。

   4.混用未命名参数和带名参数,即decorate("Hello", right = "]>>>"),得到[Hello]>>>。注:未命名参数要排在前面。


变长参数

  Scala函数可以接受可变长度参数列表,如:

scala> :paste
// Entering paste mode (ctrl-D to finish)

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

// Exiting paste mode, now interpreting.

sum: (args: Int*)Int

scala> val s = sum(1, 2, 3, 4, 5, 6)
s: Int = 21
注:在复制完函数后,按Enter键后,使用Ctrl+D退出paste模式。在调用函数sum时,sum函数得到的是一个类型为Seq的参数。如果你已经有一个值的序列,则不能直接将它传入sum函数,如sum(1 to 5)是错误的,在调用sum函数之前,你需要告诉编译器你希望这个参数被当做参数序列处理,你可这样调用,在表达式后面追加: _*,即使用sum(1 to 5: _*)调用即可。


过程

  在Scala中,对于不返回值的函数有特殊的表示法。如果函数体包含在花括号当中但没有前面的=号,那么返回类型就是Unit。这样的函数被称做过程(procedure)。过程不返回值,我们调用它仅仅是为了它的副作用。


懒值

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

lazy val words = scala.io.Source.formFile("")
注:formFile参数可为本地路径-可参照scala文件操作API。懒值并不是没有额外开销,我们每次访问懒值,都会有一个方法被调用,而这个方法将会以线程安全的方式检查该值是否已被初始化。

异常

  在Scala中,异常的工作机制和Java和C++一样,即当你抛出异常时,当前的运算被中止,运行时系统查找可以接受该异常的异常处理器。控制权将在离抛出点最近的处理器恢复。如果没有找到符合要求的异常处理器,则程序退出。

  和Java一样,抛出的对象必须是java.lang.Throwable的子类,但在Scala中throw表达式有特殊类型为Nothing。不过,与Java不同的是,Scala没有"受检"异常-你不需要声明说函数或方法可能会抛出某种异常。

  在Scala中,捕获异常的语法采用的是模式匹配的语法,与Java或C++一样,更通用的异常应该排在具体的异常之后。注意,如果你不需要使用捕获的异常对象,可以使用_来替代变量名。try/finally语句让你可以释放资源,不论有没有异常发生。try/catch和try/finally的目的是互补的,try/catch语句处理异常,而try/finally语句在异常没有被处理时执行某种动作。你也可以使用单个的try/catch/finally语句处理异常并释放资源。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值