在 Elixir 中,循环遍历 Enumerable 是很常见的,通常会过滤掉一些结果并将值映射到另一个列表中。
速构是此类构造的语法糖:它们将这些常见任务分组为 for 特殊形式。
例如,我们可以将一串整数映射到它们的平方值:
速构由三部分组成:生成器、过滤器和可收集物。
生成器和过滤器
在上面的表达式中,n <- [1, 2, 3, 4] 是生成器。它实际上是生成要在速构中使用的值。任何可枚举项都可以传递到生成器表达式的右侧:
生成器表达式还支持在其左侧进行模式匹配;所有不匹配的模式都将被忽略。想象一下,我们有一个关键字列表,而不是一个范围,其中的键是原子 :good 或 :bad,我们只想计算 :good 值的平方:
除了模式匹配,还可以使用过滤器来选择某些特定元素。例如,我们可以选择 3 的倍数并丢弃所有其他元素:
速构会丢弃过滤器表达式返回 false 或 nil 的所有元素;选择所有其他值。
与使用 Enum 和 Stream 模块中的等效函数相比,速构通常提供更简洁的表示。此外,速构还允许给出多个生成器和过滤器。下面是一个接收目录列表并获取这些目录中每个文件的大小的示例:
还可以使用多个生成器来计算两个列表的笛卡尔积:
最后,请记住,速构中的变量赋值(无论是在生成器、过滤器中还是在块内)都不会反映在速构之外。
位串生成器
位串生成器也受支持,当您需要速构位串流时,它非常有用。下面的示例从二进制文件中接收像素列表,其中包含各自的红色、绿色和蓝色值,并将它们转换为每个包含三个元素的元组:
位串生成器可以与“常规”可枚举生成器混合使用,并且还支持过滤器。
:into 选项
在上面的例子中,所有推导都返回列表作为其结果。但是,通过将 :into 选项传递给推导,可以将推导的结果插入到不同的数据结构中。
例如,可以将位串生成器与 :into 选项一起使用,以便轻松删除字符串中的所有空格:
还可以将集合、映射和其他字典提供给 :into 选项。一般来说,:into 接受任何实现 Collectable 协议的结构。
:into 的一个常见用例是转换映射中的值:
让我们使用流再举一个例子。由于 IO 模块提供了流(既是 Enumerable 又是 Collectable),因此可以使用推导实现一个回显终端,该终端会回显输入内容的大写版本:
现在在终端中输入任何字符串,您将看到相同的值将以大写形式打印。不幸的是,这个例子也让你的 IEx shell 陷入了速构阶段,所以你需要按两次 Ctrl+C 才能退出。