Scala中,几乎所有的语法结构都是有值的(包括表达式和语句块...)
1 IF/ELSE结构
val s = if(x > 0) 1 else -1
等价于 if(x > 0) s = 1 else s = -1
注:既然表达式是有值的,那么必然也是有类型的。如上述表达式的类型是:Int
如果出现if分支和else分支类型不同,比如:if(x > 0) ”positive” else -1,那么整个表达式的类型是:String和Int的公共基类Any
如果一个表达式没有任何有效值,可以用Unit表示其类型,用()表示,相当于C++中的void:
如:if(x > 0) 1 else ()
默认情况下,Scala解释器只能解释一行代码,如果你想使用多行代码,如:
if(x > 0) 1
else if(x == 0) 0 else -1
则必须在else前加上{},如:
if(x > 0) {1
} else if(x == 0) 0 else -1
2 语句的结束
Scala中的语句结束时不需要加分号,除非一行内写了多条语句,如:
if (n > 0) {r = r * n; n -= 1}
如果想将一行比较长的语句写在多行中,断行时只要第一行最后一个字符不能作为语句结束符即可,例如:+ - …
s = s0 + s1 + s2 –
s3 –s4
如果是语句块的话,最好使用{,如:
if (n > 0){
r = r * n
n -= 1
}
3 Scala的语句块
在Scala中,语句块{..}的结果是一个表达式,该语句块的值就是块中最后一个表达式的值
在Scala中,赋值语句的返回类型为Unit,因此不能出现链式赋值,如:x = y = 1,这是错误的
4 输入输出
输出:
print(“benxintuzi”) 不带换行符
println(“benxintuzi”) 带换行符
printf(“Hello, %s\n”, “benxintuzi”) 格式化输出
输入:
var name = readLine(“Your name :”),用于从控制台读取一行输入,其中的参数”Your name :”为提示符,此外,还可以如下读取不同类型的内容:
val v1 = readInt()/readDouble()/readByte()/readShort()/readChar()
5 循环
While/do循环结构与C++、Java无异
Scala中的for循环结构如下:
for(i <- 表达式)
例如,for(i <- 0 util s.length){ // [0, s.length - 1]
Sum += s(i)
}
说明:Scala中并没有提供break或者continue来退出循环,如果想实现退出循环,则可以使用如下方式:
1 使用Boolean型的控制变量
2 使用嵌套函数,从函数中return
3 使用Breaks对象中的break方法,如:
import scala.util.control.Breaks._
breakable{
for(…){
if(…) break; // 退出breakable块
}
}
for循环的高级特性:
特性1:for(i <- 1 to 3; j <- 1 to 3) print(…) // 多个表达式
特性2:for(i <- 1 to 3; j <- 1 to 3 if i != j) print(…) // 注:只能加一个判断,并且前边不能有分号
特性3:for(i <- 1 to 3; from = 4 – i; j <- from to 3) print(…) // 可以使用任意多个定义
特性4:for(i <- 1 to 10) yield i % 3 // 以yield开始的循环体会构造出一个结果集合:Vector{1, 2, 0, 1, 2, 0, 1, 2, 0, 1}
6 Scala函数
1 非递归函数定义时可以不给出函数返回类型:
def abs(x : Int) = if(x >= 0) x else –x
2 递归函数必须给出返回类型:
def fact(n : Int) : Int = if(n <= 0) 1 else n * fact(n - 1)
如果没有类型,Scala解释器无法确定n * fact(n - 1)的类型是Int(回忆一下: C/C++中的结构体中,不能有包含自身的变量,但是可以有指向自身的指针,就是因为编译器无法确定结构体的大小)
3 默认参数和指定参数
def decorate(str : String, left : String = “[”, right : String = “]”) = left + str + right // left和right都带有默认值
调用decorate(“benxintuzi”)-----[benxintuzi]
调用decorate(“benxintuzi”, “<”, “>”)-----<benxintuzi>
注:在调用时,可以显示指定某个参数的值,其顺序没必要和定义时一致,如:
decorate(left = “((”, str = “tuzi”, right = “))”)-----((tuzi)) [但是不建议这样做,最好保持定义时的顺序]
4 变长参数
def sum(agrs : Int*) = {
var result = 0
for(arg <- args) result += arg
result
}
可以使用任意多个参数调用sum,如:val s = sum(1, 2, 3)
注意:如果传入的是单个区间,如val s = sum(1 to 5),则必须告诉编译器将这个参数当作序列Seq来处理,具体如下:
val s = sum(1 to 5 : _*),该语法在递归函数中常用
7 过程
如果一个函数不需要返回有效值,可以使用过程来表示,具体如下:
def box(s : String){
Var border = “-” * s.length + “--\n”
Println(border + “|” + s + “|\n” + border)
}
等价于:
def box(s : String) : Unit = {
Var border = “-” * s.length + “--\n”
Println(border + “|” + s + “|\n” + border)
}
8 Lazy Value
当val被声明为lazy时,其初始化将被推迟到首次对其调用时:
Lazy val words = scala.io.Source.fromFile(“/usr/share/dict/words”).mkSring
只有调用words时,才会打开这个文件。该机制对于开销比较大的初始化语句十分有效。
9 异常
Scala中的异常机制与C++和Java类似。比如,throw new IllegalArgumentException(“x should not be negative”)
和Java一样,抛出的异常对象必须是java.lang.Throwable的子类。
throw表达式的类型是Nothing
捕获异常采用的是模式匹配语法:
try{
Process(new URL(“…”))
} catch{
case _ : MalformedURLException => println(“Bad URL”)
case ex : IOException => ex.printStackTrace()
}
注:在不需要使用捕获到的异常时,用 _ 代替变量名
-----源自《快学Scala》 Chapter 2