当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Elixir Collectable用法及代码示例


Elixir语言中 Collectable 相关用法介绍如下。

一种遍历数据结构的协议。

Enum.into/2 函数使用此协议将可枚举插入到集合中:

iex> Enum.into([a: 1, b: 2], %{})
%{a: 1, b: 2}

为什么要收藏?

Enumerable 协议对于从集合中取出值很有用。为了支持广泛的值, Enumerable 协议提供的函数不保持形状。例如,将映射传递给 Enum.map/2 总是返回一个列表。

这种设计是故意的。 Enumerable 旨在支持无限集合、资源和其他具有固定形状的结构。例如,将值插入 Range 是没有意义的,因为它具有固定的形状,其中仅存储范围限制和步长。

Collectable 模块旨在填补 Enumerable 协议留下的空白。 Collectable.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 的简化实现。在此实现中,"collecting" 元素仅意味着通过 MapSet.put/2 将它们插入集合中。

defimpl Collectable, for: MapSet do
  def into(map_set) do
    collector_fun = fn
      map_set_acc, {:cont, elem} ->
        MapSet.put(map_set_acc, elem)

      map_set_acc, :done ->
        map_set_acc

      _map_set_acc, :halt ->
        :ok
    end

    initial_acc = map_set

    {initial_acc, collector_fun}
  end
end

所以现在我们可以调用 Enum.into/2

iex> Enum.into([1, 2, 3], MapSet.new())
#MapSet<[1, 2, 3]>

相关用法


注:本文由纯净天空筛选整理自elixir-lang.org大神的英文原创作品 Collectable。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。