2009-01-15 10 views
9

Tôi đang phát triển hệ thống Erlang và có sự cố tái diễn với thực tế là bản ghi là các macro xử lý trước thời gian biên dịch (gần như) và không thể thao túng trong thời gian chạy ... về cơ bản, tôi đang làm việc với một mẫu thuộc tính, nơi các thuộc tính được thêm vào lúc chạy đến các đối tượng trên giao diện người dùng (AS3). Lý tưởng nhất, tôi sẽ phản ánh điều này với một danh sách ở phía Erlang, vì nó là kiểu dữ liệu cơ bản, nhưng sau đó sử dụng các bản ghi trong QCL [để truy vấn bảng ETS] sẽ không thể sử dụng được. muốn truy vấn hơn ... Tôi có ít nhất 15 cột trong bảng larges, vì vậy liệt kê tất cả trong một tuyên bố chuyển đổi rất lớn (trường hợp X của) chỉ là đồng bằng xấu xí.Erlang và giới hạn bản ghi thời gian chạy

có ai có ý tưởng nào về cách thanh lịch này không? có thể một số hàm dựng sẵn để tạo các bộ dữ liệu có chữ ký thích hợp để sử dụng trong khớp mẫu (đối với QLC)?

nhờ

+0

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

Trả lời

0

Tôi không chắc tôi hoàn toàn hiểu vấn đề của bạn, nhưng tôi đã chuyển từ hồ sơ để proplists trong hầu hết các trường hợp. Chúng linh hoạt hơn nhiều và chậm hơn nhiều. Sử dụng (d) ets tôi thường sử dụng một vài lĩnh vực bản ghi để lựa chọn thô và sau đó kiểm tra các proplists trên các hồ sơ còn lại để lựa chọn chi tiết.

+0

Proplists rất tiện lợi nếu bạn không bao giờ cần pattern-match chúng (sử dụng chính của tôi là danh sách tùy chọn là 'proplists: get_value/3' cho phép bạn lấy một giá trị hoặc sử dụng một giá trị mặc định trong một thao tác. Nếu bạn muốn tuy nhiên, bạn cần bản ghi để truy cập vùng có tên. – archaelus

4

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#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.


1

Tôi giải quyết vấn đề này (đang phát triển) bằng cách sử dụng công cụ chuyển đổi phân tích cú pháp để đọc tệp .hrl và tạo các hàm trợ giúp.

Tôi đã viết tutorial trên đó tại Trap Exit.

Chúng tôi luôn sử dụng nó để tạo thông số đối sánh. Cái đẹp là bạn không cần phải biết bất cứ điều gì về tình trạng hiện tại của hồ sơ tại thời điểm phát triển.

Tuy nhiên khi bạn đang thay đổi sản xuất!Nếu hồ sơ của bạn là cơ sở của một bảng (trái ngược với định nghĩa của một trường trong một bảng) thì việc thay đổi một bản ghi bên dưới là khó khăn hơn (để đặt nó nhẹ nhàng!).