Коллекционный протокол
Протокол для обхода структур данных.
Функция 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, for: MapSet 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)
Возвращает начальный аккумулятора и функцию "сборщика".
Возвращенная функция получает терм и команду и вставляет терм в коллекционный объект при каждой команде {:cont, term}.
:done передается как команда, когда больше значений вставляться не будет. Это полезно, когда необходимо закрыть ресурсы или нормализовать значения. Коллекционный объект должен быть возвращен, когда команда - :done.
Если вставка внезапно прервана, передается :halt, и функция может вернуть любое значение, так как оно не будет использовано.
Примеры использования протокола Collectable и функции into/1 см. в документации модуля.
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.8.2/Collectable.html