Scala编程-第7章 内建控制结构- 高飞网

第7章 内建控制结构

2017-03-20 00:52:19.0

    Scala的内建结构屈指可数,公有有if、while、for、try、match和函数调用而已。几乎所有的Scala的控制结构都会产生值。

7.1 if表达式

    指令风格:

object If{
    def main(args:Array[String])={
        var filename = "default.txt"
        if(!args.isEmpty)
            filename = args(0)
    }
}

    由于If语句可以返回值,因此最好写为如下的函数式风格:

object If{
    def main(args:Array[String])={
        val filename = if(!args.isEmpty) args(0) else "default.txt"
    }
}


7.2 while循环

while循环:

object While{
    def gcdLoop(x:Long,y:Long):Long={
        var a= x
        var b= y
        while(a!=0){
            val temp = a
            a = b%a
            b = temp
        }
        b
    }
    def main(args:Array[String]){
        val v = gcdLoop(2,4)    
        println(v)
    }
}

doWhile

import scala.io.StdIn
object While{
    def main(args:Array[String]){
        var line = ""
        do{
            //line = readLine()
            line = StdIn.readLine()
            println("Read: "+line)
        }while(line!="")
    }

注:while和do while循环不能产生值。


7.3 for表达式

    下例会打印当前目录的文件

object For{
    def main(args:Array[String]){
        var filesHere = new java.io.File(".").listFiles
        for(file<-filesHere){
            println(file)
        }
    }
}

    通过使用被称为发生器(generator)的语法“file<-filesHere”,就可以遍历filesHere的元素。

    for表达式语法对任何种类的集合都有效,而不只是数组。比如对于Range

for(i<-1 to 40)print("-");println

    没有上边界的Range

for(i<-1 until 40)print("-");println

过滤

    给for循环加过滤器,多个过滤器在可以用;分隔

object For{
    def main(args:Array[String]){
        var filesHere = new java.io.File(".").listFiles
        //给for循环加入过滤器
        for(file<-filesHere 
                if(file.getName.endsWith(".scala"))){
            println(file)
        }
    }
}

嵌套枚举

    如果加入多个<-子句,可得到了嵌套的“循环”。

object For{
    def main(args:Array[String]){
        var filesHere = new java.io.File(".").listFiles
        def fileLines(file:java.io.File)=scala.io.Source.fromFile(file).getLines.toList
        def grep(pattern:String)=
        for{
            file <- filesHere
            if file.getName.endsWith(".scala")
            line <- fileLines(file)
            if line.trim.matches(pattern)
        }   
        println(file+":"+line.trim)
        grep(".*gcd.*")
    }   
}

    可以用花括号代替小括号包裹发生器和过滤器。使用花括号的好处是可以省略使用小括号时必须加的分号。


流间(mid-stream)变量绑定

    注意上面代码中重复出现的line.trim,其实可以只算一次,只要临时保存下就可以,不用val声明

object For{
    def main(args:Array[String]){
        var filesHere = new java.io.File(".").listFiles
        def fileLines(file:java.io.File)=scala.io.Source.fromFile(file).getLines.toList
        def grep(pattern:String)=
        for{
            file <- filesHere
            if file.getName.endsWith(".scala")
            line <- fileLines(file)
            trimmed = line.trim
            if trimmed.matches(pattern)
        }   
        println(file+":"+trimmed)
        grep(".*gcd.*")
    }   
}

    即上面的trimmed。


制造新集合

    到现在为止,所有的例子都是只对枚举值进行操作然后释放,除此之外,还可以创建一个值去记录每一次迭代的的

 object For{
    def main(args:Array[String]){
        var filesHere = new java.io.File(".").listFiles
        var scalaFiles = for{
            file<-filesHere
            if(file.getName.contains(".scala"))
        } yield file
        println
        scalaFiles.foreach(print)
    }   
}

    for表达式在每次执行的时候都会产生一个新值,本例中是file。当for表达式完成的时候,结果将包含了所有产生值的集合对象。对象的类型基于子句处理的集合类型。本例中结果为Array[File],因为filesHere是数组并且产生类型是File

    另外请注意放置yield关键字的地方,对于for-yield表达式的语法是这样的:

    for {子句} yield {循环体}


7.4 使用try表达式处理异常

 抛出异常

    抛出异常的语法与java的完成一样。即 throw new XXXException

object Try{
    def main(args:Array[String]){   
        half(2)
        half(3)
    }   
    def half(i:Int){
        if(i%2==0) println(i) else throw new RuntimeException("no even") 
    }   
}

捕获异常

    使用try-catch语法

object Try{
    def main(args:Array[String]){   
        half(2)
        try{
            half(3)
        }catch{
            case ex:RuntimeException => println("捕获到了异常Runtime")
            case ex:Exception=> println("捕获到了Exception异常")
        }   
    }   
    def half(i:Int){
        if(i%2==0) println(i) else throw new RuntimeException("no even") 
    }   
}

    注意:与Java的差别在于Scala里不需要捕获检查异常,或把它们声明在throws子句中。如果愿意,可以用@throws注解声明throws子句,但不是必须的。

finally子句

object Try{
    def main(args:Array[String]){   
        half(2)
        try{
            half(3)
        }catch{
            case ex:RuntimeException => println("捕获到了异常Runtime")
            case ex:Exception=> println("捕获到了Exception异常")
        }finally{
            println("finally中用来释放资源")
        }   
    }   
    def half(i:Int){
        if(i%2==0) println(i) else throw new RuntimeException("no even") 
    }   
}

生成值

    与其他Scala控制结构一样,try-catch-finally也产生值。但不要写在finally中。


7.5 匹配(match)表达式

    Scala里的match表达式类似于其他语言中的switch语句,它可以提供在多个备选项中做选择。

    与switch不同的是,match语句不用写break,对任何类型都有效。另外,它也可以产生值。

object Match{
    def main(args:Array[String]){
        val arg = args(0)
        val fullname = arg match {
            case "xuyh" => "xuyanhua"
            case "gaop" => "gaopan"
            case _ => "who"
        }   
        println(fullname)
    }   
}


7.6 不再使用break和continue


7.7 变量范围

    Scala的范围规则几乎是Java的翻版,两者只有一个差别,Scala允许在嵌套范围内定义同名变量。

object Scope{
    def main(args:Array[String]){
        var a = 10; 
        {   
            var a = 100 
            println("a:"+a)
        }   
        println("a:"+a)
    }   
}


7.8 重构指令式风格的代码