目录
- 第二章 控制结构和函数
- 1- 条件表达式
- 2- 语句终止
- 3- 块表达式和赋值
- 4- 输入和输出
- 5- 循环
- 6- 高级for循环和for推到式
- 7- 函数
- 8- 默认参数和带名参数
- 9- 可变参数
- 10- 过程
- 11- 懒值
- 12- 异常
- end
第二章 控制结构和函数
1- 条件表达式
Scala的 if/esle 语法结构与java一样, 但是在Scala中 if/else 表达式有值, 这个值就是跟在 if 或 else 之后表达式的值.
我们可以将 if/esle 表达式的值赋值于变量:
val x = 5val s = if (x > 0) 1 else -1println(s) // 1
// 等价于val x = 5var z = 0if (x > 0) z = 1 else z = -1println(z) // 1
相比较, 第一种写法更好, 因为它可以用来初始化一个 val, 而第二种写法中, z 必须是 var;
在Scala中, 每个表达式都有一个类型;
如果是混合类型, 则类型为 Any;
如果 else 部分缺失, 例如:
val y = -5val t = if (y > 0) 1println(t) // ()
等价于
val y = -5val t = if (y > 0) 1 else ()println(t) // ()
Scala没有 Switch 语句, 但是它有一个更强大的模式匹配机制;
2- 语句终止
在Scala中, 语句的终止通常使用分号 (😉 来表示, 但是大多数情况下, 分号是可选的;
Scala具有自动分号插入(Automatic Semicolon Insertion) 的功能, 因此在大多数情况下, 可以省略分号而不会影响代码的执行;
然而, 有一些情况下需要显示使用分号来终止语句, 例如:
- 在同一行写入多个语句时, 需要使用分号将他们分隔开;
- 在一行的末尾是可以继续的语句时, 需要使用分号来明确终止该语句 .
// 分号用于分隔多个语句val x = 1 ; val y = 2// 分号用于终止可以继续的语句if (x == 1) {println("x == 1") ; println("继续执行")}
3- 块表达式和赋值
在Scala中, 块表达式 (Block Expressions) 是由一对花括号 {}
包围的一系列表达式组成的结构;
在块表达式中, 最后一个表达式的值即为整个块表达式的值;
块表达式可以用于包含多个操作或计算步骤, 并且可以隐藏中间变量, 使代码更加清晰和简洁;
在块表达式中进行赋值时, 需要注意Scala中赋值语句的特性;
在Scala中, 赋值语句本身没有返回值, 或者严格来说, 其返回值为 Unit
类型 (类似于java中的void
类型);
因此, 如果一个块表达式以赋值语句结尾, 整个表达式的值将为 Unit
类型 ;
val x = 10val y = {val a = x + 5val b = a * 2b}println(y) // 输出: 30val result = {var a = 5a += 1}println(result) // 输出: ()
4- 输入和输出
使用 print 或者 println 打印一个值;
使用 printf 格式化输出;
使用 readLine
从控制台读取一行输入, 如果是读取数字, Boolean 或者字符串, 可以使用 readInt
, readDouble
, readByte
, readShort
, readLong
, readFloat
, readBoolean
或者 readChar
;
与其它方法不同, readLine
带一个参数作为提示字符串;
println("请输入文本:")val input = StdIn.readLine()println("你输入的文本是: " + input)
请输入文本:
KFC
你输入的文本是: KFC
5- 循环
Scala支持 while 循环和 for 循环, while 循环与java的 while 一样, for 循环语法如下:
for(i <- 表达式)
遍历字符串和数组时, 你通常需要使用 0 到 n-1 的区间, 这个时候可以使用 until 方法而不是 to 方法;
until 方法返回一个并不包含上限的区间;
for (i <- 1 to 10) { // 包含10, 1 - 10println(i)}
// 或者for (x <- 1 until 10) { // 不包含 10, 1 - 9println(x)}
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
6- 高级for循环和for推到式
可以使用变量 <-
表达式的形式提供多个生成器, 用分号隔开. 例如:
for(i <- 1 to 3; j <- 1 to 3)println(10 * i + j)
11
12
13
21
22
23
31
32
33
每个生成器还可以带过滤条件, 以 if
开头的 Boolean
表达式;
for(i <- 1 to 3; j <- 1 to 3 if i != j)println(10 * i + j)
12
13
21
23
31
32
如果 for
循环的循环体以 yield
开始, 则该循环会构造出一个集合, 每次迭代出集合中的一个值:
val list = for (i <- 1 to 10) yield i % 3println(list)
Vector(1, 2, 0, 1, 2, 0, 1, 2, 0, 1)
这类循环叫做 for
推导式;
7- 函数
在Scala中, 函数是一等公民, 可以像变量一样被传递、赋值和使用;
Scala中的函数可以具有参数、返回值, 并且可以嵌套定义;
函数可以被定义为匿名函数(lambda表达式), 也可以被命名并在其它地方调用;
要定义函数, 需要给出函数的名称, 参数和函数体:
def abs(x:Double) = if (x>0) x else -x
必须给出所有参数的类型, 不过, 只要函数不是递归的, 就不需要指定返回类型;
Scala编译器可以通过=
左右两侧的表达式推断出返回类型;
如果函数体需要多个表达式完成, 可以使用代码块, 块中最后一个表达式的值就是函数的返回值.
对于递归函数, 必须指定返回类型;
def abs(x: Double) = if (x>0) x else -x
// 调用函数
println(abs(2.12)) // 2.12
println(abs(-3)) // 3.0
8- 默认参数和带名参数
在Scala中, 可以使用带名参数和默认参数来提高代码的可以读性和灵活性;
带名参数允许在调用函数时指定参数的名称, 而不必按照函数定义的顺序传递参数;
默认参数允许在定义函数时为参数指定默认值, 如果调用函数时未提供该参数的值, 则会使用默认值;
示例:
// 定义一个函数, 带有默认值参数和带名参数
def greet(name: String = "Horld", greeting: String = "Hello"): Unit = {println(s"$greeting, $name!")
}// 调用函数,使用默认参数
greet() // 输出: Hello, World!
// 调用函数,使用带名参数
greet(greeting = "Hi", name = "Taerge") // 输出: Hi, Taerge!
在上面的示例中, greet
函数定义了两个带有默认值的参数 name
和 greeting
, 在调用函数时, 可以使用默认参数, 也可以通过指定参数的名称来传递参数值 .
9- 可变参数
在Scala中, 可变参数允许函数接受可变数量的参数;
这种特性使得函数可以接受任意数量的参数, 而不需要提前确定参数的数量;
可变参数在Scala中使用 *
来定义, 通常称为可变参数, 变长参数和可变长度参数;
示例:
// todo: 定义一个函数, 接受可变参数的函数def sum(args: Int*): Int = {var result = 0for (arg <- args) {result += arg}result}// 调用函数, 传递不定量的参数println(sum(1, 2, 3)) // 输出: 6println(sum(1, 2, 3, 4, 5)) // 输出: 15
在上面的示例中, sum
函数接受一个或多个整数作为参数, 并计算他们的总和;
通过在参数类型后面加上*
, 函数就可以接受不定数量的参数;
在调用函数时, 可以传递任意数量的参数, 这些参数会被收集成一个序列;
使用可变参数可以使函数更加灵活, 适用于需要处理不定数量参数的情况 .
10- 过程
在Scala中, 不返回值的函数有一种特殊的表示法, 即定义为过程(Procedure) ;
过程是指函数体包含在花括号中, 但没有等号=
来指定返回类型, 此时函数的返回类型被推断为 Unit
;
过程在Scala中用于执行一些操作而不返回任何值;
示例:
// todo: 定义一个过程, 不返回任何值def printHello(): Unit = {println("Hello, World!")}// 调用过程printHello() // 输出: Hello, World!
在上面示例中, printHello()
函数是一个过程, 它打印 “Hello, World!” 而不返回任何值;
过程在Scala中通常用于执行副作用操作, 如打印, 写入文件等, 而不需要返回结果;
通过定义过程, 可以明确表明函数的目的是执行一些操作而不产生返回值, 这有助于代码的可读性和清晰性 .
11- 懒值
在Scala中, 懒值 (lazy val) 是一种延迟初始化的特性, 它允许变量在首次访问时才进行初始化;
懒值的声明使用 lazy
关键字, 这样可以推迟变量的初始化, 直到第一次访问该变量时才进行实际的计算或赋值;
示例:
// todo: 定义一个类class Person {// 声明一个懒值lazy val age: Int = {println("lazy value age is called")22}}// 创建一个对象val person = new Person// 访问懒值println(person.age) // 第一次访问, 会初始化并输出: lazy value age is called , 输出: 22println("-------------") // 输出: -------------println(person.age) // 第二次访问, 不会重新初始化, 直接输出: 22
在上面的示例中, age
被声明为懒值, 只有在第一次访问 age
时才会执行初始化代码;
懒值通常用于延迟初始化开销较大的变量, 以提高性能和资源利用率;
懒值在Scala中是一种常用的技术, 可以帮助优化程序性能和资源利用 .
12- 异常
在Scala中, 异常处理是通过 try
、catch
和 finally
来实现的;
Scala中的异常分为可检查异常 (checked exception) 和不可检查异常 (unchecked exception) ;
Scala不强制要求捕获或声明可检查异常, 因此通常情况下, Scala中的异常处理更接近于 java中的不可检查异常处理;
示例:
// todo: 异常try {// 可能会抛出异常的代码val result = 1 / 0} catch {case e: Exception =>// 处理异常的代码println("除0异常发生: " + e.getMessage) // 输出: 除0异常发生: / by zero} finally {println("无论如何都会执行的代码") // 输出: 无论如何都会执行的代码// 释放资源的代码println("释放资源") // 输出: 释放资源}
在上面的示例中, try
块包含可能会抛出异常的代码, catch
块用于捕获特定类型的异常并处理, finally
块中的代码无论如何是否发生异常都会执行;
除了 try
、catch
和 finally
, Scala还提供了 throw
关键字用于抛出异常. 另外, Scala中也支持使用 match
表达式来处理异常, 使异常处理更加灵活;