Es klingt, als ob Sie in der Lage sein möchten, etwas wie get_record_field(Field, SomeRecord)
zu tun, wobei Field
zur Laufzeit durch Benutzerschnittstellenkennung bestimmt wird.
Sie haben Recht, dass Sie dies nicht im Standard erlang tun können, da Datensätze und die record_info
-Funktion zur Kompilierzeit erweitert und eliminiert werden.
Es gibt ein paar Lösungen, die ich benutzt oder angeschaut habe. Meine Lösung ist wie folgt:
%% Retrieves the value stored in the record Rec in field Field.
info(Field, Rec) ->
Fields = fields(Rec),
info(Field, Fields, tl(tuple_to_list(Rec))).
info(_Field, _Fields, []) -> erlang:error(bad_record);
info(_Field, [], _Rec) -> erlang:error(bad_field);
info(Field, [Field | _], [Val | _]) -> Val;
info(Field, [_Other | Fields], [_Val | Values]) -> info(Field, Fields, Values).
%% The fields function provides the list of field positions
%% for all the kinds of record you want to be able to query
%% at runtime. You'll need to modify this to use your own records.
fields(#dns_rec{}) -> fields(dns_rec);
fields(dns_rec) -> record_info(fields, dns_rec);
fields(#dns_rr{}) -> fields(dns_rr);
fields(dns_rr) -> record_info(fields, dns_rr).
%% Turns a record into a proplist suitable for use with the proplists module.
to_proplist(R) ->
Keys = fields(R),
Values = tl(tuple_to_list(R)),
lists:zip(Keys,Values).
Eine Version davon (das Beispiel Laufzeit Zugriff auf die #dns_rec
und #dns_rr
Datensätze aus inet_dns.hrl
gibt), die hier zur Verfügung stellt ist: rec_test.erl
Sie können auch erweitern Dieses dynamische Feld-Lookup für die dynamische Generierung von Matchspecs zur Verwendung mit ets:select/2
oder mnesia:select/2
wie unten gezeigt:
%% Generates a matchspec that does something like this
%% QLC psuedocode: [ V || #RecordKind{MatchField=V} <- mnesia:table(RecordKind) ]
match(MatchField, RecordKind) ->
MatchTuple = match_tuple(MatchField, RecordKind),
{MatchTuple, [], ['$1']}.
%% Generates a matchspec that does something like this
%% QLC psuedocode: [ T || T <- mnesia:table(RecordKind),
%% T#RecordKind.Field =:= MatchValue]
match(MatchField, MatchValue, RecordKind) ->
MatchTuple = match_tuple(MatchField, RecordKind),
{MatchTuple, [{'=:=', '$1', MatchValue}], ['$$']}.
%% Generates a matchspec that does something like this
%% QLC psuedocode: [ T#RecordKind.ReturnField
%% || T <- mnesia:table(RecordKind),
%% T#RecordKind.MatchField =:= MatchValue]
match(MatchField, MatchValue, RecordKind, ReturnField)
when MatchField =/= ReturnField ->
MatchTuple = list_to_tuple([RecordKind
| [if F =:= MatchField -> '$1'; F =:= ReturnField -> '$2'; true -> '_' end
|| F <- fields(RecordKind)]]),
{MatchTuple, [{'=:=', '$1', MatchValue}], ['$2']}.
match_tuple(MatchField, RecordKind) ->
list_to_tuple([RecordKind
| [if F =:= MatchField -> '$1'; true -> '_' end
|| F <- fields(RecordKind)]]).
Ulf Wiger hat auch eine parse_transform geschrieben, Exprecs, die das mehr oder weniger automatisch für Sie tut. Ich habe es nie ausprobiert, aber Ulfs Code ist normalerweise sehr gut.
Es würde helfen, wenn Sie einen Pseudo-Code Beispiel von dem, was Sie gerne tun könnten, geben. – archaelus