2010-10-22 40 views
1

Je rencontre un problème qui devrait être stupidement facile à résoudre. Après this, j'essaie d'accéder à un champ dans un enregistrement. Voici un exemple simplifié qui présente mon problème:Erreur de syntaxe lors de l'accès à un champ dans un enregistrement

-module(test). 
-export([test/0]). 

-record(rec, {f1=[], f2=[], f3=[]}). 

test() -> 
    Rec = #rec{f1=[1,2,3], f3=[4,5,6]}, 
    Fields = record_info(fields, rec), 
    loop(Fields, Rec). 

loop([Field|Fields], Rec) -> 
    [Rec#rec.Field|loop(Fields, Rec)]; %% <-- This is line 12. 
loop([], _Rec) -> 
    []. 

Lorsque je tente de compiler test, je reçois une erreur de syntaxe:

./test.erl:12: syntax error before: Field 

Qu'est-ce que je fais mal?

+1

Le problème est que vous essayez d'emballer une course préoccupation de temps dans la compilation. Cela signifie que vous essayez d'évaluer et de remplacer Field par sa valeur réelle [qui est disponible pendant l'exécution du programme] pendant la compilation du programme. Généralement, le problème est résolu par le prétraitement ou la métaprogrammation. Malheureusement, je ne sais pas quelle est la meilleure approche pour Erlang. – Damg

Répondre

2

Si vous souhaitez uniquement énumérer les valeurs d'enregistrement, vous pouvez utiliser element/2 et énumérer les éléments de 2 (the first element is a record name) à tuple_size (Record).

Si vous souhaitez accéder à des champs d'enregistrement par nom au moment de l'exécution, vous pouvez créer proplist auxiliaire au moment de la compilation comme ceci:

Fields = lists:zip(record_info(fields, rec), 
        lists:seq(2, record_info(size, rec))) 

Notez que record_info() toujours évalué au moment de la compilation.

Et puis la valeur du champ de requête avec fonction similaire:

get_record_value(Name, Record, Fields) -> 
    case proplists:get_value(Name, Fields) of 
     undefined -> 
      undefined; 
     N when is_integer(N) -> 
      element(N, Record) 
    end. 
+0

J'accepte celui-ci, car il résout le problème énoncé dans la question, mais il s'est avéré que mon code pourrait être restructuré pour ne pas avoir à faire cela du tout (j'ai fini par couper environ la moitié de mon code). Hourra! – nmichaels

1

Les enregistrements sont convertis en tableaux à la compilation, ce qui signifie que tous les accès aux champs sont également convertis en appels erlang: element. Ainsi, les variables ne peuvent pas être utilisées car les noms de champs doivent être connus au moment de la compilation - comme Damg a déjà répondu. Les «solutions de contournement» que je connais sont soit en utilisant des listes de propriétés, des dicts, etc. au lieu des enregistrements, soit en utilisant exprecs de Ulf Wiger pour générer des fonctions d'accès aux enregistrements.

0

Une autre façon est de convertir l'enregistrement dans un proplist et à l'aide du module bibliothèque proplists pour itérer ou dans des domaines spécifiques d'accès. Cet exemple:

-module(test). 
-export([start/0]). 
-record(test, {value1, value2, value3}). 

start() -> 
    R = #test{value1=1, value2=2, value3=3}, 
    Fields = record_info(fields, test), 
    Values = tl(tuple_to_list(R)), 
    lists:zip(Fields, Values). 

produira les proplist suivants:

> c("test"). 
> Proplist = test:start(). 
[{value1,1},{value2,2},{value3,3}] 

Ensuite, par exemple pour obtenir la valeur du champ value2:

> proplists:get_value(value2, Proplist). 
2