Scala编程(第七章:内建的控制结构)

1.if表达式:Scala的if是一个能返回值的表达式,更为精简。如:

val filename=if (!arg.isEmpty) args(0) else "default.txt"

可以不用println(filename),而是写成这样:

println(if (!arg.isEmpty) args(0) else "default.txt")

 

2.while循环:Scala的while循环跟其他语言用起来没多大差别。默认没有continue和break语句。如:

def gcdLoop(x:Long,y:Long):Long={
  var a=x
  var b=y
  while(a!=0){
    val tmp=a
    a=b%a
    b=a
  }
  b
}

Scala也有do-while循环,跟while类似,只不过它是在循环体之后执行条件检查而不是在循环体之前。如:

var line=""

do{
 line=reaLine()
 println("Read: "+line)
} while (line !="")

while和do-while虽然有返回值,但返回一个类型为Unit的值,这个值叫作单元值,写作()。可以尝试比较:

val a=while (false){}
println(a==())
//打印:true

另一个相关返回单元值的语法结构是对var的赋值。例如,当你尝试在Scala中像Java(或c/c++)的while循环惯用法那样使用while循环时,会遇到问题:

var line=""
while((line=readLine())!="")//并不可行!
  println("Read:"+line)

编译器会给出警告:用!=对类型Unit的值和String做比较将永远返回true。在Java中赋值语句的结果是被赋上的值,而在Scala中赋值语句的结果永远是单元值()。因此,赋值语句“line=readLine()”将永远返回()。由于while循环没有返回值,纯函数式编程语言通常都不支持。求两个数的最大公约数可以用递归来解决:

def gcd(x:Long,y:Long):Long=
  if (y==0) x else gcd(y,x%y)

 

3.for表达式

遍历集合

val fileLines=Source.fromFile(fileUrl).getLines.toList
for (line<-fileLines)
  println(line)

通过“line<-fileLines”这样的生成器语法,我们将遍历fileLines的元素。每一次迭代,一个新的名为line的val都会被初始化成一个元素的值。for表达式的语法可以用于任何类型的集合,而不仅仅是数组。可以用“1 to 5”这样的语法来创建Range,并用for来遍历它们:

for (i<-1 to 5)
  println("Iteration "+i)

如果不想被遍历的值中包含区间的上界(值5),可以用until而不是to。

过滤:过滤器是for表达式的圆括号中的一个if子句。如,列出包含“def”的行:

val fileLines=Source.fromFile(fileUrl).getLines.toList
for (line<-fileLines if line.contains("def"))
  println(line)

也可以用如下代码达到同样的目的:

val fileLines=Source.fromFile(fileUrl).getLines.toList
for (line<-fileLines)
 if (line.contains("def"))
  println(line)

这段代码跟之前的输出没有区别,可能看上去对于指令式编程背景的程序员来说更为熟悉。可以随意包含更多的过滤器,直接添加if子句即可:

val fileLines=Source.fromFile(fileUrl).getLines.toList
for (line<-fileLines 
     if line.contains("def")
     if line.length<10 )
  println(line)

嵌套迭代:如果添加多个<-子句,你将得到嵌套的“循环”。注意:在for括号中会默认为一条语句,如有其它语句可以用“;”断句。

产出一个新的集合:具体做法是在for表达式的代码体之前加上关键字yield。

for-yield表达式的语法如下:for 子句 yield 代码体

for语句测试代码:

    for (line <- fileLines
         if line.contains("def");
         s <- line;
         ss = "hhhh";
         if ss.contains("h")
    ) yield ss
   val a= for (i<-1 to 5)
      yield {i+1}
    println(a)

 

4.用try表达式实现异常处理:Scala的异常处理跟其它语言类似。方法除了正常地返回某个除外,也可以通过抛出异常终止执行。

抛出异常

val half = if (n % 2 == 0) n / 2 
           else throw new RuntimeException("n must be even")

虽然看上去有些自相矛盾,在Scala中throw是一个有结果类型的表达式,从技术上讲,抛出异常这个表达式的类型是Nothing。

捕获异常

val n=3
try {
   val half = if (n % 2 == 0) n / 2 else throw new RuntimeException("n must be even")
   println(half)
}catch {
   case ex:FileNotFoundException=>println("File error")
   case ex:RuntimeException=>{println("???");println("Runtime error")}

可以这样来捕获异常。catch的语法之所以是这样,为的是与Scala的一个重要组成部分,模式匹配,保持一致。

finally子句:可以将那些不论是否抛出异常都想执行的代码以表达式的形式包在finally子句里。例如,你可能想要确保某个打开的文件要被正确关闭,哪怕某个方法因为抛出了异常而退出:

val file = new FileReader("input.txt")
try{
//使用文件
}finally{
  file.close()
}

跟Scala的大多数其他控制结构一样,try-catch-finally最终返回一个值。如:

val n=2
val half=try {
   if (n % 2 == 0) n / 2 else throw new RuntimeException("n must be even")
}catch {
   case ex:FileNotFoundException=>println("File error")
   case ex:RuntimeException=>{println("???");println("Runtime error")}
}finally {
   println()
}
println(half)
//打印 1

 

5.match表达式:Scala的match表达式让你从若干可选项中选择。就像其他语言中的switch语句那样。match表达式当然也可以返回值。如:

val n=2
val a=n match {
  case 1=>println("?")
  case 2=>222
  case 3=>{println("???");println("hah")}
  case _=>println("...")
}
println(a)
//打印 : 
//222

缺省的样例以下划线(_)表示,这个通配符在Scala中经常被用来表示某个完全不知道的值。Scala的match和Java的switch相比;Scala每个可选项的最后没有break,Scala的break是隐含的,并不会出现某个可选项执行完继续执行下一个可选项的情况。还有一个就是Scala支持任何常量和字符串等都可以用作样例,Java的case语句支持整型、枚举和字符串常量。

 

6.没有break和continue的日子:Scala去掉了这两个命令,虽然Scala支持指令式和函数式风格的编程,但它更倾向于函数式编程,以换取语言的简单。不过就算没有了break和continue,一样有很多其他方式来编程。如果是while语句,可以通过递归来解决相似的问题。如果要用,还是提供了break方法:

import  scala.util.control.Breaks._
breakable{
    while (true){
      println("???")
      break()
    }
}

break类实现breal的方法是抛出一个异常,然后由外围的breakable捕获。

 

7.变量作用域:Scala的作用域规则几乎跟Java完全一样。Java和Scala的一个区别是Scala允许你在嵌套的作用域内定义同名的变量,不过为了保障代码的可读性避免这样做。关于作用域最常见的例子是花括号一般都会引入一个新的作用域,除了一点,Scala中有时候可以用花括号{}来代替圆括号()。

 

8.对指令式代码进行重构:用函数式风格打印乘法口诀表:

    def makeRowSeq(row: Int) = for (col <- row to 9) yield {
      val prod = (col * row).toString
      if(prod.length == 1)
        prod + " "
      else
        prod
    }
    def makeRow(row: Int) = makeRowSeq(row).mkString(" ")
    def multiTable() = {
      val tableSeq = for (col <- 1 to 9) yield {
        makeRow(col)
      }
      tableSeq.mkString("\n")
    }
    println(multiTable())

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值