代码改变世界

【转】Simple Erlang record wrapper

2011-11-25 23:52  码农.KEN  阅读(650)  评论(1编辑  收藏  举报

原文出处:http://rouxviljoen.blogspot.com/2011/05/simple-erlang-record-wrapper.html

 

Most systems I have seen has some desired method of passing data from one application to another, whether it be records,proplists or something else. If you use mnesia, you end up dealing with a lot of records. This is where the pain for most startup Erlang programmers start. To use the awesome syntactic sugar of records, the module using the record needs to have it declared. The easy option is just to put the record definition in a .hrl file and include it in every module that uses the record, but that is not really viable if there are hundreds of different records passing through several modules per functional process.

Here we will quickly create a simple wrapper that can be used to give you access to your records without having to include your .hrl's everywhere.

To use this wrapper you will need to create a small module:

 
-module(first_record).
-define(NAME, test_record).
-record(?NAME, {id,name,surname}).
-include("wrapper.hrl").
 

Now for the wrapper, create a file called "wrapper.hrl"

-export([fields/0,
rget/2,
rset/2,
new/0
]).

fields() -> record_info(fields,?NAME).
new() -> #?NAME{}.

rget(Field,Record) when is_atom(Field), is_record(Record,?NAME) ->
element(fld_index(Field),Record);
rget(Fields,Record) when is_list(Fields), is_record(Record,?NAME) ->
[ rget(Field,Record) || Field <- Fields].

rset(Fields,Record) when is_list(Fields), is_record(Record,?NAME) ->
lists:foldl(fun({Field,Value}, Rec) -> setelement(fld_index(Field), Rec, Value) end, Record, Fields).

fld_index(Field) -> fld_index(fields(),Field,1).
fld_index([],Field,Index) ->
error_logger:error_report([{module,?MODULE},{function,fld_index},{arguments,[[],Field,Index]},{error,invalid_field},{stack,erlang:get_stacktrace()}]),
erlang:error(invalid_field);
fld_index([Field|_T],Field,Index) -> Index + 1;
fld_index([_H|T],Field,Index) -> fld_index(T,Field,Index+1).

 

Now lets compile it and test:

38> c(first_record).
{ok,first_record}
39> l(first_record).
{module,first_record}
40> Record = first_record:new().
{test_record,undefined,undefined,undefined}
41> UpdatedRecord = first_record:rset([{name,"Roux"},{surname,"Viljoen"}],Record).
{test_record,undefined,"Roux","Viljoen"}
42> first_record:rget(name,UpdatedRecord).
"Roux"
43> first_record:rget([name,surname],UpdatedRecord).
["Roux","Viljoen"]



So rget/2 is equal to #REC.Field or #REC{Field1=Value1,Field2=Value2}=RecordVariable
and rset/2 is equal to #REC{Field=Value,Field2=Value2}

By using this little wrapper.hrl you can now create modules to represent the records and use the modules to manipulate the records.

Just remember that this example can be implemented in many different ways, depending on your requirement.