首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Erlang和运行时记录限制

Erlang和运行时记录限制
EN

Stack Overflow用户
提问于 2009-01-15 15:33:49
回答 2查看 2.8K关注 0票数 9

我正在开发一个Erlang系统,由于记录(几乎)是编译时预处理宏,并且不能在运行时操作,这一事实反复出现问题……基本上,我使用的是属性模式,其中属性在运行时添加到前端(AS3)上的对象。理想情况下,我会在Erlang端用一个列表来反映这一点,因为它是一种基本的数据类型,但是在QCL中使用记录来查询ETS表是不可能的,因为要使用它们,我必须明确地说明我想要查询哪个记录属性……我在大型表中至少有15列,所以在一个巨大的switch语句(case X of)中列出所有这些列是非常难看的。

有没有人知道如何优雅地解决这个问题?也许是一些内置的函数,用于创建具有适当签名的元组,以便在模式匹配中使用(用于QLC)?

谢谢

EN

回答 2

Stack Overflow用户

发布于 2009-02-26 19:35:23

这听起来像是您希望能够做类似于get_record_field(Field, SomeRecord)的事情,在这种情况下,Field在运行时由用户界面代码决定。

您说得对,您不能在标准erlang中做到这一点,因为记录和record_info函数在编译时被扩展和消除。

有几个我用过或看过的解决方案。我的解决方案如下:(该示例提供了对来自inet_dns.hrl#dns_rec#dns_rr记录的运行时访问)

代码语言:javascript
复制
%% 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).

编译后的版本可以在这里获得:rec_test.erl

您还可以将此动态字段查找扩展为动态生成匹配规范,以便与ets:select/2mnesia:select/2一起使用,如下所示:

代码语言:javascript
复制
%% 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还编写了一个名为Exprecs的parse_transform,它或多或少会自动为您完成这项工作。我从未尝试过,但Ulf的代码通常非常好。

票数 4
EN

Stack Overflow用户

发布于 2009-01-20 22:05:29

我不确定我是否完全理解您的问题,但在大多数情况下,我已经从记录转移到了proplists。它们更灵活,速度也更慢。使用(d)ets时,我通常使用一些记录字段进行粗略选择,然后检查其余记录上的proplist以进行详细选择。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/447188

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档