web-dev-qa-db-fra.com

Quel est l'avantage des listes de mots clés?

Dans elixir, nous avons des cartes:

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

Nous avons également des listes de mots clés:

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

Pourquoi les deux?

Syntaxe? Est-ce parce que les listes de mots-clés ont une syntaxe plus flexible leur permettant d'être définies sans curlys et même sans crochets comme dernier paramètre d'un appel de fonction? Alors pourquoi ne pas donner à Maps ce sucre syntaxique?

Clés en double? Est-ce parce que les listes de mots clés peuvent avoir des clés en double? Pourquoi voudriez-vous à la fois un accès au style de carte et des clés en double?

Performance? Est-ce parce que les listes de mots clés ont de meilleures performances? Alors pourquoi avoir Maps? Et les cartes ne devraient-elles pas être plus performantes pour rechercher des membres par clé qu'une liste de tuples?

JS Array et Ruby Hash comme l'apparence? C'est tout?

Je comprends que ce sont structurellement des représentations de données différentes. Il me semble que les listes de mots-clés dans elixir servent à compliquer le langage grâce à une syntaxe exceptionnelle (3 variantes syntaxiques différentes), un chevauchement de cas d'utilisation avec des cartes et un avantage peu clair.

Quel est l'avantage d'utiliser les listes de mots clés?

99
greggreg
                   ┌──────────────┬────────────┬───────────────────────┐
                   │ 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⁴                 │
└──────────────────┴──────────────┴────────────┴───────────────────────┘

Les listes de mots clés sont légères et ont une structure simple en dessous, ce qui les rend très flexibles. Vous pouvez les considérer comme du sucre de syntaxe au-dessus d'une convention Erlang, ce qui facilite l'interface avec Erlang sans écrire de code trop laid. Par exemple, des listes de mots clés sont utilisées pour représenter des arguments de fonction, qui est une propriété héritée d'Erlang. Dans certains cas, les listes de mots clés sont votre seul choix, surtout si vous avez besoin de clés en double ou d'une commande. Ils ont simplement des propriétés différentes des autres alternatives, ce qui les rend plus adaptés à certaines situations et moins à d'autres.

Les cartes (et les structures) sont utilisées pour stocker les données de charge utile réelles, car elles ont une implémentation basée sur le hachage. Les listes de mots clés en interne ne sont que des listes qui doivent être parcourues pour chaque opération, de sorte qu'elles n'ont pas les propriétés des structures de données de valeurs-clés classiques comme l'accès en temps constant.

Elixir a également introduit HashDict comme solution de contournement pour le mauvaise performance des cartes au moment où il a été écrit . Cependant, cela est maintenant corrigé depuis Elixir 1.0.5/Erlang 18.0 et HashDictsera déconseillé dans les futures versions .

Si vous approfondissez la bibliothèque standard d'Erlang, il existe encore plus de structures de données qui stockent des paires clé/valeur:

  • proplists - similaire aux listes de mots clés Elixir
  • maps - identique aux maps Elixir
  • dict - dictionnaires de valeurs-clés construits à partir de primitives Erlang
  • gb_trees - arbre général équilibré

Vous disposez également de ces options lorsque vous devez stocker des paires clé/valeur sur plusieurs processus et/ou machines virtuelles:


¹ D'une manière générale, mais bien sûr cela dépend ™.

² Le meilleur des cas est simplement ajouté à une liste.

³ S'applique à Elixir 1.0.5 et supérieur, peut être plus lent dans les anciennes versions.

HashDict est désormais obsolète.

⁵ Nécessite une recherche linéaire qui scanne en moyenne la moitié des éléments.

140
Patrick Oscity

Le principal avantage des listes de mots clés est une compatibilité ascendante avec les bases de code existantes pour les élixirs et erlang.

Ils ajoutent également du sucre de syntaxe s'ils sont utilisés comme arguments de fonctions qui ressemblent par exemple à a Ruby syntaxe:

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

Le principal inconvénient de l'utilisation des listes de mots clés est qu'il n'est pas possible d'effectuer une correspondance de modèle partielle sur celles-ci:

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]

Étendons-le aux arguments de fonction. Imaginez que nous devons gérer une fonction multiclause basée sur une valeur de l'une des options:

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

Cela n'exécutera jamais le do_special_thing:

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

Avec des arguments de carte, cela fonctionnera:

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

Les cartes n'autorisent qu'une seule entrée pour une clé particulière, tandis que les listes de mots clés permettent de répéter la clé. Les cartes sont efficaces (en particulier à mesure qu'elles grandissent) et peuvent être utilisées dans la mise en correspondance des motifs d'Elixir.

En général, utilisez des listes de mots clés pour des choses telles que les paramètres de ligne de commande et pour passer des options, et utilisez des cartes (ou une autre structure de données, le HashDict) lorsque vous voulez un tableau associatif.

2
Subhash Chandra