Spec-Zone.ru › Elixir 1.16

Источник Collectable протокол

Протокол для обхода структур данных.

Функция Enum.into/2 использует этот протокол для вставки перечислимого в коллекцию:

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

Почему Collectable?

Протокол 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.new([1, 2, 3])

Чтобы показать, как можно реализовать протокол, мы снова можем обратиться к упрощенной реализации для MapSet. В этой реализации "собирание" элементов просто означает вставку их в множество через 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.new([1, 2, 3])

Резюме

Типы

command()
t()

Все типы, которые реализуют этот протокол.

Функции

into(collectable)

Возвращает начальный аккумулирующий элемент и функцию "коллектора".

Типы

command()Источник

@type command() :: {:cont, term()} | :done | :halt

t()Источник

@type t() :: term()

Все типы, которые реализуют этот протокол.

Функции

into(collectable)Источник

@spec into(t()) ::
  {initial_acc :: term(), collector :: (term(), command() -> t() | term())}

Возвращает начальный аккумулирующий элемент и функцию "коллектора".

Принимает collectable, который может быть использован в качестве начального аккумулирующего элемента, который будет передан функции.

Функция коллектора получает термин и команду и вставляет термин в аккумулирующий элемент collectable при каждой команде {:cont, term}.

:done передаётся как команда, когда больше значений вставлять не нужно. Это полезно, когда необходимо закрыть ресурсы или нормализовать значения. Когда команда :done, возвращается collectable.

Если вставка прерывается, передаётся :halt, и функция может вернуть любое значение, так как оно не будет использоваться.

Примеры использования протокола Collectable и функции into/1 можно найти в документации модуля.

Скачать версию ePub

Создано с помощью ExDoc (v0.32.2) для язык программирования Elixir

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.16.3/Collectable.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API