Scala编程第3版第七章(内建控制结构)
2020-02-20 23:54:44    28    0    0
yuziyue

赋值语句返回值

在Java中,赋值语句的结果是被赋上的值(在本例中就是从标准输入读取的一行文本),而在Scala中赋值语句的结果永远是单元值()。因此,赋值语句"line=readLine()"将永远返回(),而不是""。这样一来,while循环的条件检查永远都不会为false,循环将无法终止。

while ((line=readLine()) != "")
    println("good")


for表达式

// 包含右边界
for (i <- 1 to 4)
    println(i)
1
2
3
4

// 不包含右边界
for (i <- 1 until 4)
    println(i)
1
2
3


for表达式过滤器

// 添加一个过滤器
val filesHere = (new java.io.File(".")).listFiles
for (file <- filesHere if file.getName.endsWith(".py"))
    println(file)

// 添加多个过滤器。多个条件表示 and 的关系
val filesHere = (new java.io.File(".")).listFiles
for (
    file <- filesHere
    if file.getName.endsWith(".py")
    if file.isFile
)println(file)


// for循环的括号里面如果有多条语句,需要用分号隔开
val embed = List(List(1, 2), List(3, 4, 5), List(6, 7, 8, 9))
for (
    outer <- embed if outer.length == 3;
    inner <- outer if inner == 3
)println(outer, inner)


// 可以用大括号替代圆括号,此时多条语句可以省略分号
val embed = List(List(1, 2), List(3, 4, 5), List(6, 7, 8, 9))
for {
    outer <- embed if outer.length == 3
    inner <- outer if inner == 3
}println(outer, inner)


// 找出以 .py 文件结尾的文件内 def 定义函数的行
val filesHere = (new java.io.File(".")).listFiles
for (
    file <- filesHere
    if file.getName.endsWith(".py")
    if file.isFile;
    line <- scala.io.Source.fromFile(file).getLines().toList
        if line.matches(".*def .*")
)println(file + ": " + line)


for循环和yield使用

for循环中的 yield 会把当前的元素记下来,保存在集合中,循环结束后将返回该集合。Scala中for循环是有返回值的。如果被循环的是Map,返回的就是Map,被循环的是List,返回的就是List,以此类推。

val number = List(1, 2, 3, 4, 5, 6, 7, 8)
val even = for (i <- number if i % 2 == 0) yield i
println(even)


try表达式异常处理

Scala中throw是一个有结果类型的表达式,但是这个结果永远也不会被用到,因为已经报异常了,程序中断。

val n = 3
val half = if (n % 2 == 0) n / 2 else throw new RuntimeException("n must be even")
java.lang.RuntimeException: n must be even
  ... 28 elided

half
res23: AnyVal = ()


异常处理块 try-catch-finally

try {
    // 正常处理
} catch {
    case ex: FileNotFoundException => // 捕获到这个异常后处理
    case ex: IOException => // 捕获到这个异常后处理
} finally {
    // 不论是否有异常,都会执行这里的内容
}


try-catch-finally最终返回一个值

import java.net.URL
import java.net.MalformedURLException

// urlFor 函数里面如果生成URL产生异常,将返回一个默认的URL
def urlFor(path: String) = 
    try {
        new URL(path)
    } catch {
        case e: MalformedURLException => new URL("http://www.scala-lang.org")
    }



跟Java一样,当finally子句包含一个显式的返回语句,那么这个返回值将会“改写”任何在之前的try代码块或某个catch子句中产生的值。

// 将返回 2
def f(): Int = try return 1 finally return 2

// 将返回 1
def g(): Int = try 1 finally 2

所以最好避免在finally子句中返回值,最好将finally子句用来处理一些清理工作,比如关闭一个打开的文件。


match表达式

Scala中的match表达式和其他语言的switch类似。如果没有匹配,则执行 _ 后面的默认语句。

val firstArg = if (args.length > 0) args(0) else ""
firstArg match {
    case "beijing" => println("The Great Wall")
    case "guizhou" => println("bigdata center")
    case _ => println("Hello World")
} 


Scala的match表达式跟Java的switch相比,有一些重要的区别。其中一个区别是任何常量、字符串等都可以用作样例,而不仅限于Java的case语句支持的整型、枚举和字符串常量。符串等都可以用作样例,而不仅限于Java的case语句支持的整型、枚举和字符串常量。另一个区别是在每个可选项的最后并没有break,在Scala中break是隐含的。


不过Scala的match表达式跟Java的switch相比最显著的不同,在于match表达式会返回值。

val firstArg = if (args.length > 0) args(0) else ""
val yourChoice = firstArg match {
    case "beijing" => "The Great Wall"
    case "guizhou" => "bigdata center"
    case _ => "Hello World"
}
println(yourChoice)


没有break和continue的日子

最简单的方式是用if换掉每个continue,用布尔值换掉每个break。比如比较如下的java代码和scala代码

java 代码

// java 代码
int i = 0;
boolean foundIt = false;
while (i < args.length) {
    if (args[i].startsWith("-")) {
        i += 1;
        continue;
    }
    if (args[i].endsWith(".scala") {
        fountIt = true;
        break;
    }
    i += 1;
}

scala 代码

// scala 代码
var i = 0
var foundIt = false
while (i < args.length && !foundIt) {
    if (!args(i).startsWith("-")) {
        if (args(i).startsWith(".scala"))
            foundIt = true
    }
    i += 1
}

scala 代码写成递归函数

// scala 代码
def searchFrom(i: Int): Int = {
    if (i >= args.length) - 1
    else if (args(i).startsWith("-")) searchFrom(i+1)
    else if (args(i).endsWith(".scala")) i
    else searchFrom(i+1)
}
val i = searchFrom(0)

// Scala 编译器实际上并不会对上面的代码生成递归函数,由于所有的递归调用都发生在函数尾部,编译器会生成与while循环类似的代码。


还是想使用break

scala.util.control 包的Break类给出了一个break方法,可以被用来退出包含它的用breakable标记的代码块。Break类实现的break的方法是抛出一个异常,然后由外围的breakable的方法的应用所捕获,因此对break的调用并不需要跟breakable的调用放在同一个方法内。

import scala.util.control.Breaks.{breakable, break}

val num = List(1,2,3,4,5)
breakable {
    for (i <- num) {
        println(i)
        if (i == 3) break
    }
}


变量作用域

需要注意的一个Scala跟Java的区别是,Java不允许你在内嵌的作用域使用一个跟外部作用域内相同名称的变量。在Scala程序中,内嵌作用域中的变量会遮挡(shadow)外部作用域中相同名称的变量,因为外部作用域的同名变量在内嵌作用域内将不可见。

val a = 1
{
    val a = 2
    println(a)
}
println(a)

// 会先打印出2,然后在打印出1

为了更好的可读性,通常更好的做法是选一个新的有意义的变量名,而不是(用同样的名称)遮挡某个外部作用域的变量。





上一篇: Spark基本框图

下一篇: Scala编程第3版第六章(函数式对象)

28 人读过
文档导航