Có vẻ như bạn muốn có thể làm điều gì đó như get_record_field(Field, SomeRecord)
trong đó Field
được xác định khi chạy theo mã giao diện người dùng.
Bạn nói đúng là bạn không thể làm điều này trong tiêu chuẩn erlang làm hồ sơ và chức năng record_info
được mở rộng và loại bỏ tại thời gian biên dịch.
Có một vài giải pháp mà tôi đã sử dụng hoặc xem xét. Giải pháp của tôi là như sau: (ví dụ cho phép truy cập thời gian chạy để các hồ sơ #dns_rec
và #dns_rr
từ inet_dns.hrl
)
%% 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).
Một phiên bản của này mà biên dịch có sẵn ở đây: rec_test.erl
Bạn cũng có thể mở rộng tìm kiếm trường động này để tạo ra các trận đấu kết nối động để sử dụng với ets:select/2
hoặc mnesia:select/2
như hình dưới đây:
%% 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 cũng đã viết một parse_transform, Exprecs, ít nhiều bạn cũng có thể tự động thực hiện điều này. Tôi chưa bao giờ thử nó, nhưng mã của Ulf thường rất tốt.
Sẽ hữu ích nếu bạn đưa ra ví dụ về mã psuedo về những gì bạn muốn có thể làm. – archaelus