Яка перевага списків ключових слів?


101

У еліксирі у нас є Карти:

> 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)

Чому обидва?

Синтаксис? Це тому, що списки ключових слів мають більш гнучкий синтаксис, що дозволяє визначати їх без фігурних і навіть без дужок як останній параметр виклику функції? Тоді чому б не дати Карту цей синтаксичний цукор?

Дублікати ключів? Це тому, що у списках ключових слів можуть бути повторювані ключі? Чому ви хочете отримати доступ до стилю карти та копії ключів?

Продуктивність? Це тому, що списки ключових слів мають кращу ефективність? Тоді навіщо Карти? І чи не повинні карти виглядати ефективніше під час пошуку членів за ключем, ніж список кортежів?

JS Array і Ruby Hash люблять зовнішність? Це все?

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

Яка перевага від використання списків ключових слів?

Відповіді:


143
                   ┌──────────────┬────────────┬───────────────────────┐
                   │ 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. У деяких випадках списки ключових слів - це ваш єдиний вибір, особливо якщо вам потрібні повторювані ключі або замовлення. Вони просто мають інші властивості, ніж інші альтернативи, що робить їх більш придатними для одних ситуацій і меншими для інших.

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

Еліксир також вводиться HashDictяк вирішення для поганої роботи карт під час написання . Однак це тепер виправлено як Elixir 1.0.5 / Erlang 18.0, а HashDict в наступних версіях буде застаріло .

Якщо ви заглибитесь у стандартну бібліотеку Ерланга, є ще більше структур даних, які зберігають пари ключів / значень:

  • прополіси - схожі на списки ключових слів Elixir
  • карти - те саме, що і карти Elixir
  • dict - словники ключових значень, побудовані з примітивів Ерланга
  • gb_trees - загальне збалансоване дерево

У вас також є такі параметри, коли вам потрібно зберігати пари ключів / значень у кількох процесах та / або VM:

  • ets / dets - (на основі диска) Термін зберігання Erlang
  • mnesia - розподілена база даних

Ly Взагалі кажучи, але, звичайно, це залежить ™.

² Найкращий випадок - це лише попереднє створення списку.

³ Застосовується до Elixir 1.0.5 і вище, у старих версіях може бути повільніше.

HashDictзараз застаріла.

⁵ Потрібен лінійний пошук, який в середньому сканує половину елементів.


1
Дозволення повторюваних ключів та замовлення - це не переваги, а різні властивості. Вам потрібно вибрати структуру даних, яка відповідає вашим потребам.
праворуч

2
Строго кажучи, так, але вони можуть виявитися корисними, якщо вам потрібні ці властивості - ось що я мав на увазі.
Патрік Осіті

@PatrickOscity: У такому випадку, напевно, їх краще класифікувати як вимоги ?
Гонки легкості на орбіті

11
@greggreg Є ще одна неявна перевага наявності списків ключових слів: ми розрізняємо структуровані та неструктуровані дані. Карти надзвичайно корисні для структурованих даних із відомим набором ключів, а ключові слова - ні. Сьогодні більшість карт використовується для структурованих даних, а ключові слова ми залишаємо для необов'язкових. Якби у нас були лише карти, я думаю, добра частина цього розрізнення була б втрачена.
Жозе Валім

1
Насправді так і було, карти - це шлях, який слід їхати з erlang 18.
Papipo

12

Основна перевага списків ключових слів - зворотна сумісність із існуючою базою кодів elixir та erlang.

Вони також додають синтаксичний цукор, якщо його використовують як аргументи функцій, що нагадує, наприклад, синтаксис рубіну:

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]

Розширимо це на аргументи функції. Уявіть, що нам потрібно обробити функцію мультиклаузу на основі значення одного з варіантів:

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

2

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

Загалом, використовуйте списки ключових слів для таких речей, як параметри командного рядка та для проходження параметрів, а також використовуйте карти (або іншу структуру даних, HashDict), коли потрібно асоціативний масив.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.