文章目录
1.表达式
表达式是返回一个值的代码单元
简单表达式的例子:
更复杂的表达式的例子:
表达式最重要的是它返回的值,表达式的关键就是要返回捕获和使用的值
2.用表达式定义值和变量
语法:
- 值
val <identifier>[: <type>] = <expression>
- 变量
var <identifier>[: <type>] = <expression>
由于字面量值也是一种表达式,这些定义更全面,而且更准确。实际上,表达式也是定义Scala中大多数语法的坚实基础。
3.表达式块
可以使用大括号({和})结合多个表达式创建一个表达式块。表达式有自己的作用域,可以包含表达式块中的局部值和变量。块中的最后一个表达式将作为整个表达式块的返回值。
来看一个例子,下面这行代码中有两个表达式,如下所示:
我们关心的是amount,所以就可以将包含“x”值的表达式结合到一个快中,如下所示:
块中的最后一个表达式“x + 10”确定了块的返回值。
表达式块可以根据需要跨多行,重写前面的例子,不再包含分号,如下所示:
表达式块也可以嵌套,每一级表达式块都有自己的值和变量,一个简单的三层嵌套的表达式块如下所示:
4.语句
语句就是不返回值的表达式。语句的返回类型为Unit,这种类型指示没有值。Scala编程中常用的语句包括println()调用以及值和变量定义。
例子如下:
repl重复了x的定义,但是不会返回可以用来创建新值的具体数据。
与表达式块不同,语句块不返回值。由于语句块没有输出,通常用来修改现有的数据,或者完成应用之外的修改
5.if…else表达式块
在形式化语法中,Scala只支持一个“if和可选的“else”块,而不能识别“else if”块
下面来分析具体的使用场景。
- if表达式
语法:
if (<Boolean expression>) <expression>
这里的Boolean expression(布尔表达式)指示一个将返回true或false的表达式
例子如下:
使用if块作为表达式的问题在于:它们只能有条件地返回一个值。如果布尔表达式返回false,例如:
因为值的类型没有指定,编译器就会使用类型推导来确定最合适的类型。可能会返回一个String或Unit,所以编译器会选择根类Any,因为这是String(扩展了AnyRef)和Unit(扩展了AnyVal)共同的根类。
- if…else表达式
与单个的"if"块不同,“if-else”块很适合处理表达式
语法:
if (<Boolean expression>) <expression>
else <expression>
例子如下:
if…else块是编写条件逻辑的一种简单而常用的方法,因为有if…else表达式的存在,所以Scala没有三元表达式
不过,Scala还有更精巧的方法来实现条件逻辑,即使用匹配表达式
6.匹配表达式
匹配表达式类似于C和Java的“Switch”语句,首先会计算一个输入项,并执行第一个“匹配”模式,然后返回它的值。与C和Java的“Switch”语句类似,Scala的匹配表达式支持一个默认或通配的“全包型”模式。但与它们不同的是,Scala的匹配表达式只能有0个或1个模式可以匹配,而且不会从一个模式“贯穿”到下一个模式,也不需要“break”语句来避免这种贯穿行为
实际上,大多数Scala开发人员更愿意使用匹配表达式而不是"if…else"块,因为匹配表达式更具有表属性,而且语法更简洁。
- 匹配表达式
语法:
<expression> match{
case <pattern match> => <expression>
[case...]
}
注意:Scala官方支持箭头(=>)后面跟有多个表达式,不过并不推荐这种做法,因为这会降低可读性
例子如下:
- 模式替换式
语法:
case <pattern 1> | <pattern 2> .. => <one or more expressions>
利用模式替换式,通过对多个模式重用相同的case块,可以避免重复的代码
例子如下:
但是,如果没有与输入表达式相匹配的模式,就会发生错误(scala.MatchError),表示了这个错误是由于匹配表达式无法处理其输入。
为了避免错误破坏匹配表达式,可以使用一个通配的“全匹配”模式,或者增加足够的模式来涵盖所有可能的输入。
7.用通配模式匹配
在匹配表达式中可以使用两种通配模式,值绑定和通配符(即“下划线”)
利用值绑定(value binding)或变量绑定(variable binding),将把匹配表达式的输入绑定到一个局部值,然后可以在case块的体中使用。
- 值绑定模式
语法:
case <identifier> => <one or more expressions>
由于模式包含所绑定的值名,并没有要匹配的具体模式,因此值绑定是一个通配模式,它能匹配任何输入值
例子如下:
- 通配符模式
语法:
case _ => <one or more expressions>
通配符是一个下换线(_)字符,相当于一个匿名占位符,最后将在运行时替换为一个表达式的值。与值绑定类似,下划线通配符没有提供可以匹配的具体模式,因为这是一个通配模式,可以匹配任何输入值。
不能在箭头右侧访问通配符,这与值绑定不同。如果需要在case块中访问通配符的值,可以考虑使用值绑定,或者直接访问匹配表达式的输入(如果可以)
例子如下:
在这里,下划线通配符将与运行时匹配表达式的输入值匹配。不过,不能像访问绑定值那样在case块中访问通配符,因此,要用匹配表达式的输入创建包含相关信息的println语句
8.用模式哨卫匹配
模式哨卫向值绑定模式增加一个if表达式,从而可以为匹配表达式增加条件逻辑。使用模式哨卫时,只有当表达式返回true时模式才匹配
语法:
case <pattern> if <Boolean expression> => <one or more expressions>
例子如下:
9.用模式变量匹配类型
利用匹配表达式完成模式匹配还有一种方法,即匹配输入表达式的类型。如果匹配,模式变量可以把输入值转换为一个不同类型的值,然后可以在case块中使用这个新值和类型
语法:
case <identifier> : <type> => <one or more expressions>
对于模式变量的命名,除了值和常量的有关命名要求外,唯一的限制是它们必须以一个小写字母开头。
Scala中支持多态类型,这就是一个线索,由此可以看出匹配表达式的作用。
例子如下:
匹配表达式能够根据这个值的实际类型来匹配,而不是根据它给定的类型完成匹配
10.循环
循环一词指反复地执行一个任务,可能包括迭代处理一个数据范围或者一直重复直至一个布尔表达式返回false
Scala中最重要的循环结构就是for循环(for-loop),For循环可以迭代处理一个数据范围,每次迭代会执行一个表达式,并返回所有表达式返回值的一个集合(可选)。for循环可以灵活定制,支持嵌套迭代、过滤和值绑定
首先,需要介绍一个名为Range(范围)的新的数据结构,可以用来迭代处理一个数字序列。需要使用to或until操作符并指定开始和结束整数来创建范围,to操作符会创建一个包含列表(inclusive list),until操作符则创建一个不包含列表(exclusive list)
- 定义数值范围
语法:
<starting integer> [to|until] <ending integer> [by increment]
- 用基本for循环迭代处理
语法:
for(<identifier> <- <iterator>) [yield] [<expression>]
示例如下:
可以使用yield关键字来将迭代语句转换为一个表达式,它会返回各个消息而不是把它们打印出来,示例如下:
11.迭代器哨卫
类似匹配表达式中的模式哨卫,迭代器哨卫也称为过滤器,可以为迭代器增加一个if表达式。使用迭代器哨卫时,可以跳过一次迭代,除非If表达式返回true
语法:
for (<identifier> <- <iterator> if <Boolean expression>) ...
例子如下:
迭代器哨卫也可以与迭代器分开,出现在单独的一行上,例子如下:
12.嵌套迭代器
嵌套迭代器是增加到一个for循环的额外的迭代器,迭代总数随迭代器个数倍增。之所以称为嵌套迭代器,是因为把它们增加到同一个循环中与写为单独的嵌套循环有同样的效果。
例子如下:
13.值绑定
for循环中的一个常见做法是基于当前迭代在表达式块中定义临时值或变量。在Scala中,另一种替代方法是在for循环的定义中使用值绑定(value binding),它们的工作是一样的,不过使用值绑定有助于尽可能降低表达式块的规模和复杂性。
绑定值可以用于嵌套迭代器、迭代器哨卫和其他绑定值。
语法:
for(<identifier> <- <iterator> ; <identifier> = <expression>) ...
例子如下(计算2的0次幂到2的8次幂):
14.While和Do/While循环
除了for循环,Scala还支持“while"和“do/while”循环,这会重复一个语句直到一个布尔表达式返回false。不过,在Scala中这些循环没有for循环那么常用,因为它们不是表达式,不能用来获得值。
- while循环
语法:
while(<Boolean expression>) statement
例子如下:
- do/while循环
语法:
do while(<Boolean expression>) statement
15.练习
- 给定一个字符串名,写一个匹配表达式,如果非空则返回相同的字符串,如果为空就返回字符串“n/a”
- 给定一个双精度数,写一个表达式,如果这个数大于0则返回“greater”,如果等于0返回“same”,如果小于0则返回“less”。你能用if…else块来写这个表达式吗?使用匹配表达式呢?
(1).if…else块
(2).匹配表达式
- 打印数字1到100,每行包含一组5个数,例如:
1,2,3,4,5,
6,7,8,9,10,
…
-
写一个表达式,打印数字1到100,不过3的倍数除外,3的倍数要打印为“type",另外要把5的倍数打印为”safe",对于3以及5的倍数(如15),则打印为”typesafe“
作者注:这题我写的有问题…希望有大佬能在留言区指正