第二部分 控制结构和函数
第1节 if 表达式
Scala中 if 表达式有返回值。
如果if 和 else 的返回值类型不一样,那么就返回两个返回值类型公共的父类。
-- if 语句有返回值
val x = 10
val s = if (x > 0) 1 else -1
-- 多分支if 语句
val s = if (x==0)
0
else if (x > 1)
1
else
0
-- 如果返回的类型不一致就返回公共的父类
val s = if (x > 0)
"positive"
else
-1
-- 缺省 else 语句;s1/s2的返回类型不同
val s1 = if (x > 0) 1 等价于 val s1 = if (x > 0) 1 else ()
val s2 = if (x > 0) "positive" 等价于 val s2 = if (x > 0) "positive" else ()
第2节 for 表达式
Scala中,for循环语法结构:for (i <- 表达式 / 集合),让变量 i遍历<-右边的表达式/集合的所有值。
Scala为for循环提供了很多的特性,这些特性被称之为 for守卫式 或 for推导式。
-- 基本结构。使用to实现左右两边闭合的访问区间
for (i <- 1 to 10) {
println(s"i = $i")
}
-- 基本结构。使用until实现左闭右开的访问区间
for (i <- 1 until 10) {
println(s"i = $i")
}
-- 双重循环。条件之间使用分号分隔
for(i <-1 until 5; j <- 2 until 5){
println(i * j )
}
-- 使用变量
for (i <- 1 to 3 ;j = 4-i){
println(i * j )
}
-- 守卫语句。增加 if 条件语句
for (i <- 1 to 10; j <- 1 to 10 if i==j){
println(s"i * j = $i * $j = ${i * j}")
}
-- 使用 yield 接收返回的结果,这种形式被称为for推导式
val result = for (i <- 1 to 10) yield i
-- 使用大括号将生成器、守卫、定义包含在其中;并以换行的方式来隔开它们
for { i <- 1 to 3
from = 4 - i
j <- from to 3
}
println(s"i = $i; j = $j")
第3节 while 表达式
Scala提供了与 Java 类似的while和do...while循环。while语句的本身没有任何返回值类型,即while语句的返回结果是Unit类型的 () 。
Scala内置控制结构特地去掉了 break 和 continue。
特殊情况下如果需要终止循环,可以有以下三种方式:
- 使用Boolean类型的控制变量
- 使用return关键字
- 使用breakable和break,需要导入scala.util.control.Breaks包
// while循环
var flag = true
var result = 0
var n = 0
while (flag) {
result += n
n += 1
println("res = " + result)
println("n = " + n)
if (n == 10) {
flag = false
}
}
// for循环
var flag = true
var res = 0
for (i <- 0 until 10 if flag) {
res += i
println("res = " + res )
if (i == 5) flag = false
}
/**
*1+2+3+4
*
* @return
*/
def addInner() {
for (i <- 0 until 10) {
if (i == 5) {
return
}
res += i
println("res = " + res)
}
}
def main(args: Array[String]): Unit = {
addInner()
}
def main(args: Array[String]): Unit = { // 需要导包
import scala.util.control.Breaks._
var res = 0
breakable {
for (i <- 0 until 10) {
if (i == 5) {
break
}
res += i
}
}
println("res = " + res)
}
第4节 函数
函数体中最后一句为返回值的话,可以将return 去掉;如果一个函数体只有一句代码,大括号可以去掉;
如果一个函数没有返回值,其返回类型为Unit , 并且 “=” 号可以去掉,这样的函数被称为过程;
可以不声明函数的返回类型,返回类型可通过自动类型推断来完成,但递归函数的返回类型必须声明;
备注:建议明确声明函数的返回值,即使为Unit
-- 定义函数
def add(x: Int, y: Int): Int = {
x+y
}
-- 递归函数必须声明返回类型
def fibonacci(n: Int): Long = {
if(n > 0){
if(n==1 || n==2)
1
else
fibonacci(n - 1) + fibonacci(n - 2)
}
}
-- 参数的默认值
def add(x: Int, y: Int=10): Int = {
x+y
}
add(1)
add(1, 20)
-- 带名参数
def add(x: Int=1, y: Int=10, z: Int): Int = {
x+y+z
}
-- 现在要求x=1, y=10, c=100
add(1, 10, 100)
add(z=100)
-- 变长参数。x的数据类型可以简单的认为是Array[Int]
def add(x: Int*): Int = {
x.sum
}
// 告诉编译器这个参数被当做参数序列处理。使用 parameter: _* 的形式
val arr = (1 to 10).toArray
add(arr: _*)
// 变长参数只能出现在参数列表的尾部,只能有一个
// Error: *-parameter must come last
def add1(x: Int*, y: String) = {
... ...
}
第5节 懒值
当 val 被声明为lazy时(var不能声明为lazy),它的初始化将被推迟,直到首次对此取值,适用于初始化开销较大的场景。
// 语句立刻执行,发现文件不存在,报错
val file1 = scala.io.Source.fromFile("src/test111.scala")
// 文件不存在时,不会报错。因为语句此时并没有被执行
lazy val file2 = scala.io.Source.fromFile("src/test111.scala")
println("OK1")
file2.getLines().size
// 先打印OK!,才报错
第6节 文件操作
导入scala.io.Source后,可引用Source中的方法读取文本文件的内容
import scala.io.{BufferedSource, Source}
object FileDemo {
def main(args: Array[String]): Unit = {
//注意文件的编码格式,如果编码格式不对,那么读取报错
val file: BufferedSource = Source.fromFile("... ...", "GBK");
val lines: Iterator[String] = file.getLines()
for (line <- lines) {
println(line)
}
//注意关闭文件
file.close()
}
}
如果要将文件内容转数组,直接调用toArray。
读取网络资源
import scala.io.{BufferedSource, Source}
object FileDemo2 {
def main(args: Array[String]): Unit = {
val source: BufferedSource = Source.fromURL("http://www.baidu.com")
val string: String = source.mkString
println(string)
source.close()
}
}
Scala没有内建的对写入文件的支持。要写入文本文件,可使用 java.io.PrintWriter
import java.io.PrintWriter
object FileDemo3 {
def main(args: Array[String]): Unit = {
val writer = new PrintWriter("../a.txt")
for(i <- 1 to 100){
writer.println(i)
writer.flush()
}
writer.close()
}
}