Elixir 流

2023-12-15 13:53 更新
Elixir提供了支持懒惰操作的String模块来作为Enum的替代品:
iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?) |> Enum.sum
7500000000

流是懒惰的,组合的枚举接口。

在上述例子中,1..100_000 |> Stream.map(&(&1 * 3))返回了一个数据类型,实际上是一个流,它代表了map计算在范围1..100_000中:

iex> 1..100_000 |> Stream.map(&(&1 * 3))
#Stream<[enum: 1..100000, funs: [#Function<34.16982430/1 in Stream.map/2>]]>

而且它们是可组合的,因为我们可以用管连接许多流操作:

iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?)
#Stream<[enum: 1..100000, funs: [...]]>

流没有生成中间列表,而是构建了一系列的计算,它们只会在我们将潜在的流传递给​Enum​模块时才会被调用。流在处理大量的,有可能是无限的,集合时非常有用。

Stream模块中的许多函数接受任何枚举体作为参数,并返回一个流作为结果。也有用于创建流的函数。例如,Stream.cycle/1用于创建一个将给定枚举体无限循环的流,注意不要以这种流为参数调用例如Enum.map/2之类的函数,因为他们会无限循环下去:

iex> stream = Stream.cycle([1, 2, 3])
#Function<15.16982430/2 in Stream.cycle/1>
iex> Enum.take(stream, 10)
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1]

另一方面,​Stream.unfold/2​可以用于从给定的初始值中生成多个值:

iex> stream = Stream.unfold("hełło", &String.next_codepoint/1)
#Function<39.75994740/2 in Stream.unfold/2>
iex> Enum.take(stream, 3)
["h", "e", "ł"]

另一个有趣的函数是​Stream.resource/3​,它可以用于包裹源代码,保证它们在枚举之前是开启的且之后是关闭的,即使在失败的案例中。例如,我们可以用它流一个文件:

iex> stream = File.stream!("path/to/file")
#Function<18.16982430/2 in Stream.resource/3>
iex> Enum.take(stream, 10)

上述例子将会获得所选文件的前十行。这意味着流可以很好地处理巨大的文件,即使是像网络资源那样的慢资源。

EnumStream模块中的函数数量也许一开始很吓人,但你会一个案例一个案例地熟悉他们。首先专注于Enum模块,只在要求懒惰性的情形下使用Stream模块,例如处理慢资源,或巨大的,可能无限的集合。

我们将要讲到Elixir的核心特性,进程,它使得我们能以一种简单易懂的方式编写并发,并行和分布式的程序。

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号