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!