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())