Question

J'essaie de refactoriser un code dont je dispose pour un logiciel qui collecte le statut actuel des agents dans une file d'attente. Actuellement, pour chacun des 6 événements que j'écoute, je vérifie dans une table Mnesia si un agent existe et modifie certaines valeurs de la ligne en fonction de l'événement ou l'ajoute comme nouveau si l'agent n'existe pas. Actuellement, j'ai cette transaction Mnesia dans chaque événement et bien sûr, c'est un tas de code répété pour vérifier l'existence d'agents, etc.

J'essaie de le changer pour qu'il y ait une fonction comme change_agent / 2 que j'appelle parmi les événements qui le gère pour moi.

Mes problèmes sont bien sûr des enregistrements ... Je ne trouve aucun moyen de les créer de manière dynamique ou de fusionner deux d'entre eux ou quoi que ce soit. De préférence, il y aurait une fonction que je pourrais appeler comme:

change_agent("001", #agent(id = "001", name = "Steve")).
change_agent("001", #agent(id = "001", paused = 0, talking_to = "None")).
Était-ce utile?

La solution

J'ai écrit du code il y a quelque temps qui fusionne deux enregistrements. N’est pas entièrement dynamique, mais avec les macros, vous pouvez facilement l’utiliser pour plusieurs enregistrements.

Cela fonctionne comme suit: la fonction merge / 2 prend deux enregistrements et les convertit en listes avec l'enregistrement vide pour référence (le type d'enregistrement est défini au moment de la compilation et doit être. Il s'agit de la partie "non dynamique" ). Celles-ci sont ensuite exécutées via la fonction générique merge / 4, qui utilise des listes et prend des éléments de A s'ils sont définis, sinon de B s'ils sont définis, ou enfin de Default (toujours défini).

Voici le code (veuillez excuser la faible coloration syntaxique Erlang de StackOverflow):

%%%----------------------------------------------------------------------------
%%% @spec merge(RecordA, RecordB) -> #my_record{}
%%%     RecordA = #my_record{}
%%%     RecordB = #my_record{}
%%%
%%% @doc Merges two #my_record{} instances. The first takes precedence.
%%% @end
%%%----------------------------------------------------------------------------
merge(RecordA, RecordB) when is_record(RecordA, my_record),
                             is_record(RecordB, my_record) ->
    list_to_tuple(
        lists:append([my_record],
                     merge(tl(tuple_to_list(RecordA)),
                           tl(tuple_to_list(RecordB)),
                           tl(tuple_to_list(#my_record{})),
                           []))).

%%%----------------------------------------------------------------------------
%%% @spec merge(A, B, Default, []) -> [term()]
%%%     A = [term()]
%%%     B = [term()]
%%%     Default = [term()]
%%%
%%% @doc Merges the lists `A' and `B' into to a new list taking
%%% default values from `Default'.
%%%
%%% Each element of `A' and `B' are compared against the elements in
%%% `Default'. If they match the default, the default is used. If one
%%% of them differs from the other and the default value, that element is
%%% chosen. If both differs, the element from `A' is chosen.
%%% @end
%%%----------------------------------------------------------------------------
merge([D|ATail], [D|BTail], [D|DTail], To) ->
    merge(ATail, BTail, DTail, [D|To]); % If default, take from D
merge([D|ATail], [B|BTail], [D|DTail], To) ->
    merge(ATail, BTail, DTail, [B|To]); % If only A default, take from B
merge([A|ATail], [_|BTail], [_|DTail], To) ->
    merge(ATail, BTail, DTail, [A|To]); % Otherwise take from A
merge([],        [],        [],        To) ->
    lists:reverse(To).

N'hésitez pas à l'utiliser comme bon vous semble.

Autres conseils

Il est difficile d'écrire des fonctions d'accès génériques pour les enregistrements. Une solution consiste à utiliser la bibliothèque "exprecs" , qui générera du code pour les fonctions d’accès aux enregistrements de bas niveau.

Ce que vous devez faire est d’ajouter les lignes suivantes à un module:

-compile({parse_transform, exprecs}).
-export_records([...]).  % name the records that you want to 'export'

La convention de dénomination des fonctions d'accès peut paraître étrange, mais elle a été inspirée par une proposition de Richard O'Keefe. Il est au moins cohérent et peu susceptible de se heurter aux fonctions existantes. (:

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top