Collectable
可收集协议
遍历数据结构的协议。
该Enum.into/2
函数使用此协议将枚举插入到集合中:
iex> Enum.into([a: 1, b: 2], %{})
%{a: 1, b: 2}
为什么要收藏?
该Enumerable
协议有助于从集合中取出值。为了支持各种各样的值,Enumerable
协议提供的功能不会保持形状。例如,传递一个地图Enum.map/2
总是返回一个列表。
这个设计是有意的。Enumerable
用于支持无限的集合、资源和其他固定形状的结构。例如,将值插入到范围中是没有意义的,因为它有一个固定的形状,仅存储范围限制。
该Collectable
模块旨在填补Enumerable
协议留下的空白。into/1
可以被看作是相反的Enumerable.reduce/3
。如果Enumerable
要取出数值,那Collectable.into/1
就是将这些数值收集到一个结构中。
实例
为了展示如何手动使用该Collectable
协议,让我们来看看它的实现MapSet
。
iex> {initial_acc, collector_fun} = Collectable.into(MapSet.new())
iex> updated_acc = Enum.reduce([1, 2, 3], initial_acc, fn elem, acc ->
...> collector_fun.(acc, {:cont, elem})
...> end)
iex> collector_fun.(updated_acc, :done)
#MapSet<[1, 2, 3]>
为了展示协议如何实现,我们可以再次看看实现MapSet
。在这个实现中,“收集”元素仅仅意味着将它们插入到集合中MapSet.put/2
。
defimpl Collectable do
def into(original) do
collector_fun = fn
set, {:cont, elem} -> MapSet.put(set, elem)
set, :done -> set
_set, :halt -> :ok
end
{original, collector_fun}
end
end
摘要
类型
command()t()
功能
into(collectable)
返回初始累加器和“收集器”函数。
类型
command()
command() :: {:cont, term} | :done | :halt
t()
t() :: term
函数
into(collectable)
into(t) :: {term, (term, command -> t | term)}
返回一个初始累加器和一个“收集器”函数。
返回的函数接收一个术语和一个命令,并将该项注入到每个{:cont, term}
命令。
:done
当没有更多值将被注入时作为命令传递。这在需要关闭资源或标准化值时非常有用。必须在收到命令时返回收集器:done
。
如果注射突然中断,:halt
函数可以返回任何值,因为它不会被使用。
有关如何使用Collectable
议定书和into/1
请参阅模块文档。