В чем преимущество списков ключевых слов?


в elixir у нас есть карты:

> map = %{:a => "one", :b => "two"} # = %{a: "one", b: "two"}
> map.a                             # = "one"
> map[:a]                           # = "one"

у нас также есть списки ключевых слов:

> kl = [a: "one", b: "two"]       # = [a: "one", b: "two"]
> kl2 = [{:a, "one"},{:b, "two"}] # = [a: "one", b: "two"]
> kl == kl2                       # = true
> kl[:a]                          # = "one"
> kl.a                            # = ** (ArgumentError)

почему так?

синтаксис? это потому, что списки ключевых слов имеют более гибкий синтаксис, позволяющий им определяться без curlys и даже без скобок в качестве последнего параметра вызова функции? Тогда почему бы не дать карты этого синтаксического сахара?

Дубликаты Ключей? это потому, что списки ключевых слов могут иметь дубликаты ключей? Зачем вы хотите как доступ к стилю карты, так и дубликаты ключей?

производительность? это потому, что списки ключевых слов имеют лучшую производительность? Тогда зачем нужны карты? И разве карты не должны быть более эффективными при поиске членов по ключу, чем список кортежей?

массив JS и Ruby хэш, как внешний вид? что это?

Я понимаю, что структурно они разные представления данных. Мне кажется, что списки ключевых слов в elixir служат для усложнения язык через исключительный синтаксис (3 различных синтаксических варианта), перекрытие вариантов использования с картами и неясное преимущество.

в чем преимущество использования списков ключевых слов?

3 94

3 ответа:

                   ┌──────────────┬────────────┬───────────────────────┐
                   │ Keyword List │ Map/Struct │ HashDict (deprecated) │
┌──────────────────┼──────────────┼────────────┼───────────────────────┤
│ Duplicate keys   │ yes          │ no         │ no                    │
│ Ordered          │ yes          │ no         │ no                    │
│ Pattern matching │ yes          │ yes        │ no                    │
│ Performance¹     │ —            │ —          │ —                     │
│ ├ Insert         │ very fast²   │ fast³      │ fast⁴                 │
│ └ Access         │ slow⁵        │ fast³      │ fast⁴                 │
└──────────────────┴──────────────┴────────────┴───────────────────────┘

списки ключевых слов легкие и имеют простую структуру под ними, что делает их очень гибкими. Вы можете думать о них как о синтаксическом сахаре поверх соглашения Erlang, что упрощает интерфейс с Erlang без написания слишком уродливого кода. Например, списки ключевых слов используются для представления аргументов функции, которая является свойством, унаследованным от Erlang. В некоторых случаях списки ключевых слов являются вашим единственным выбором, особенно если вам нужны дубликаты ключей или заказ. Они просто есть различные свойства, чем другие альтернативы, которые делают их более подходящими для некоторых ситуаций и меньше для других.

карты (и структуры) используются для хранения фактических данных полезной нагрузки, поскольку они имеют реализацию на основе хэша. Списки ключевых слов внутри-это просто списки, которые необходимо пройти для каждой операции, поэтому они не имеют свойств классических структур данных ключ-значение, таких как постоянный доступ времени.

эликсир также представил HashDict как временное решение плохая производительность карт в то время, когда она была написана. Однако, сейчас эта проблема решена, как эликсир 1.0.5/Эрланг 18.0 и HashDictбудет удален в будущих версиях.

если вы копнете глубже в стандартной библиотеке Erlang, есть еще больше структур данных, которые хранят пары ключ / значение:

  • proplists - похоже на списки ключевых слов Elixir
  • карты - то же, что и эликсир карты
  • дикт – словари ключевых значений, построенные из примитивов Эрланга
  • gb_trees – общая сбалансированное дерево

у вас также есть эти параметры, когда вам нужно хранить пары ключ / значение в нескольких процессах и / или виртуальных машинах:

  • ets/ dets - (диск на основе) Erlang срок хранения
  • mnesia – распределенной база данных

1, Вообще говоря, но конечно зависит™.

2 лучший случай - это просто добавление к списку.

3 применяется к Elixir 1.0.5 и выше, может быть медленнее в старых версиях.

HashDict теперь не рекомендуется.

⁵ требуется линейный поиск, который в среднем сканирует половину элементов.

главным преимуществом списков ключевых слов является обратная совместимость с существующими elixir и Erlang codebase.

они также добавляют синтаксический сахар, если он используется в качестве аргументов функций, которые напоминают, например, синтаксис ruby:

def some_fun(arg, opts \ []), do: ...
some_fun arg, opt1: 1, opt2: 2

основной недостаток использования списков ключевых слов заключается в том, что на них невозможно выполнить частичное сопоставление шаблонов:

iex(1)> m = %{a: 1, b: 2}
%{a: 1, b: 2}
iex(2)> %{a: a} = m
%{a: 1, b: 2}
iex(3)> a
1
iex(4)> k = [a: 1, b: 2]
[a: 1, b: 2]
iex(5)> [a: a] = k
** (MatchError) no match of right hand side value: [a: 1, b: 2]

давайте расширим его до аргументов функции. Представьте, что нам нужно обработать функцию multiclause на основе a значение одного из вариантов:

def fun1(arg, opt1: opt1) when is_nil(opt1), do: do_special_thing
def fun1(arg, opts), do: do_regular_thing

def fun2(arg, %{opt1: opt1}) when is_nil(opt1), do: do_special_thing
def fun2(arg, opts), do: do_regular_thing

этого никогда не будет выполнять do_special_thing:

fun1("arg", opt1: nil, opt2: "some value")
doing regular thing  

с аргументами карты это будет работать:

fun2("arg", %{opt1: nil, opt2: "some value"})
doing special thing

карты позволяют только одну запись для конкретного ключа, а списки ключевых слов позволяют повторить ключ. Карты эффективны (особенно по мере их роста), и они могут быть используется при подборе эликсира по шаблону.

В общем случае используйте списки ключевых слов для таких вещей, как параметры командной строки и для передачи параметров, а также используйте карты (или другую структуру данных, HashDict), когда вам нужен ассоциативный массив.