Les structures de données Elixir sont immuables. C'est génial du point de vue de la confiance que nos données ne seront pas corrompues au-delà de la reconnaissance dans un autre morceau de code non pertinent, mais c'est un peu ennuyeux lorsque nous devons changer une structure profondément imbriquée.
Nous avons une brillante abstraction Access
, qui simplifie considérablement quatre opérations de base sur des objets profondément imbriqués en utilisant les fonctions exportées par défaut du Kernel
:
Ces quatre mousquetaires (et d'Artagnan Kernel.get_and_update_in/{2,3}
sont généralement utilisés quelque chose comme ceci:
iex> users = %{"john" => %{age: 27, mood: ""}, "meg" => %{age: 23}}
Il est pratique et fonctionne dans de nombreux cas ... sauf pour ceux oĂč cela ne fonctionne pas. Pour utiliser Access
, vous devez connaßtre le chemin d'accÚs à l'élément cible, et tout cela nécessite une quantité importante de code passe-partout afin de mettre à jour plusieurs valeurs imbriquées à la fois (par exemple, supprimez toutes les feuilles avec la valeur nil
ou mettez en Ă©toile le contenu de tous les champs qui n'ont pas besoin d'ĂȘtre affichĂ©s dans les journaux).
Pour offrir des remises en gros sur l'utilisation de structures imbriquées, la bibliothÚque Iteraptor
a été créée.
TL; DR:
Itérer tout ce que vous pouvez répéter comme par magie à Elixir . Pour le rendre itérable, implémentez simplement le protocole Enumerable
pour ce type particulier. Vous pouvez regrouper les passages en pipelines, cartographier, rĂ©duire, filtrer, Ă©claircir ... Pardonnez mon français, oui. Tous ceux qui ont passĂ© au moins huit heures avec Elixir ont certainement vu (et peut-ĂȘtre mĂȘme Ă©crit) quelque chose comme ceci:
~w| | |> Enum.map(&String.capitalize/1) |> Enum.each(fn capitalized_name -> IO.puts "Hello, #{capitalized_name}!" end)
C'est vraiment trÚs pratique. Cependant, le code devient rapidement lourd lorsqu'il s'agit de structures profondément imbriquées, telles qu'une carte avec des mots - clés imbriqués, des listes, etc. Un bon exemple de ceci est tout fichier de configuration contenant des sous-sections imbriquées.
Le nombre de questions sur Stack Overflow avec la question «comment puis-je changer la structure imbriquĂ©e?» M'a forcĂ© Ă enfin crĂ©er cette bibliothĂšque. La mise en Ćuvre chez Elixir semble un peu dĂ©routante, car tout autour est immuable, et vous ne pouvez pas simplement descendre les branches de la structure jusqu'aux feuilles, en changeant tout ce dont vous avez besoin en place. Vous aurez besoin d'une batterie, comme, cependant, sous n'importe quel capot d'un code fonctionnel. Changer les structures imbriquĂ©es est probablement le seul exemple que j'ai vu dans ma vie oĂč la mutabilitĂ© facilite les choses.
En plus des précurseurs de carte habituels, j'ai ajouté une implémentation pour stocker la valeur au plus profond de la structure, ce qui crée des clés intermédiaires selon les besoins. Il se comporte comme proposé, mais rejeté dans le noyau rubis Hash#bury
. Cette bibliothĂšque sait Ă©galement comment "jasoniser" des structures imbriquĂ©es contenant des mots clĂ©s qui ne peuvent pas ĂȘtre simplement sĂ©rialisĂ©s en json , car Ă l'intĂ©rieur, ils sont prĂ©sentĂ©s comme des listes de tuples Ă deux Ă©lĂ©ments ( [foo: :bar] == [{:foo, :bar}]
), et les tuples ne sont pas sérialisables hors de la boßte.
Alors, saluons la bibliothÚque, qui itÚre sur n'importe quelle carte / mot - clé / liste dans la queue et la criniÚre est presque aussi simple que les Enum.each/2
et Enum.map/2
.
Les possibilités
Les mots ne coûtent rien, montrez le code!
Itération, cartographie, réduction
Imbrication profonde â structure plate et vice versa
iex> %{a: %{b: %{c: 42, d: [nil, 42]}, e: [:f, 42]}} ...> |> Iteraptor.to_flatmap(delimiter: "_") #â %{"a_b_c" => 42, "a_b_d_0" => nil, "a_b_d_1" => 42, "a_e_0" => :f, "a_e_1" => 42} iex> %{"abc": 42, "abd0": nil, "abd1": 42, "ae0": :f, "ae1": 42} ...> |> Iteraptor.from_flatmap
Brioches
iex> Iteraptor.jsonify([foo: [bar: [baz: :zoo], boo: 42]], values: true) %{"foo" => %{"bar" => %{"baz" => "zoo"}, "boo" => 42}} iex> Iteraptor.Extras.bury([foo: :bar], ~w|abcd|a, 42) [a: [b: [c: [d: 42]]], foo: :bar]
Les sources sont ouvertes , la documentation est assez détaillée , nous sommes en production depuis prÚs de deux ans maintenant.
Bonne itération!