Scala学习系列-表达式1:for表达式
本篇我们将详细介绍当我们在Scala中使用for表达式时背后的故事。
for表达式的一般式
其中:
- 带
yield
关键字的for表达式我们称为for推导式,不带yield
关键字的for表达式我们称为for循环; seq
代表的是生成器、值定义、过滤器所组成的序列,它们之间用分号进行分隔,并且seq
必须以生成器作为开始元素。
推导式示例:
1 | for (p <- persons; n = p.name; if (n startsWith "To")) |
或者
1 | for { |
生成器
值定义
过滤器
for表达式的转换
转换生成器中的模式
在具体介绍转换规则之前,我们先来介绍转换任何一个生成器都需要做的第一步转换操作。我们知道生成器箭号左边是一个模式,对于每个型如:的模式,都会首先被转换为:的形式,它代表的含义是:对生成器的表达式expr
进行模式判断,只有跟pat
匹配上才会进一步应用后续转换环节;否则该生成器将被忽略,而不会抛出任何MatchError。当任何生成器进行该步转换之后,接着再使用我们后面介绍的规则进行相应的转换。
转换单个生成器的for推导式
表达式:,其中x为变量。
使用map
转换生成器:
转换单个生成器的for循环
表达式:,其中x为变量。
使用foreach
转换生成器:
转换以一个生成器和一个过滤器开始的for推导式
表达式:,其中x为变量。
首先,使用withFilter
转换过滤器:
然后,使用map
转换生成器:
转换以一个生成器和一个过滤器开始的for循环
表达式:,其中x为变量。
首先,使用withFilter
转换过滤器:
然后,使用foreach
转换生成器:
转换以两个生成器开始的for推导式
表达式:,其中x、y为变量,seq为任意的生成器、值定义和过滤的拼接序列。
首先,使用flatMap
转换第一个生成器:
然后,按照已经介绍的上述规则继续转换剩余的生成器和seq
。
转换以两个生成器开始的for循环
表达式:,其中x、y为变量。
转换为:
转换for推导式中的值定义
表达式:,其中x、y为变量,seq为任意的生成器、值定义和过滤的拼接序列。
首先,转换“定义”:,可以看出,每当生成一个新的x
,expr2
就会被计算一次,所以,如果定义变量的时候没有使用到之前生成器绑定的变量,那么这样的定义最好不要定义在for表达式中。
并非只有集合才支持for表达式
TODO
Notes
本文基于Scala2.12.13