[erlang-questions] Record fields
zxq9
zxq9@REDACTED
Fri Dec 11 12:24:05 CET 2015
On 2015年12月11日 金曜日 13:53:46 Kirill Ratkin wrote:
> Hi!
>
> I'm trying to get records fields at runtime.
> If I have record 'test' and I can do:
> record_info(fields, test).
>
> But if I do:
> R = test,
> record_info(fields, R).
>
> I get error :
> * 1: illegal record info.
>
> Documentation says: To each module using records, a pseudo function is
> added during compilation to obtain information about records.
>
> It seems it's really 'pseudo' function ....
>
> Is there alternative way to get record fields in runtime?
Not exactly, no. Records are converted to tuples, not hashes, and the way field labels are expanded is a transformation performed at compile time, when the code is converted and record syntax is all magicked away. Consider this:
=====================================================================
ceverett@REDACTED:~/Code/erlang$ cat recfind.erl
-module(recfind).
-export([find_by_phone/2, find_by_mail/2, fields/0]).
-record(contact, {fname, lname, phone=[], mail=[], city=[], street=[]}).
find_by_phone(Phone, AddressBook) ->
find(Phone, #contact.phone, AddressBook).
find_by_mail(Mail, AddressBook) ->
find(Mail, #contact.mail, AddressBook).
find(Value, Field, AddressBook) ->
case lists:keyfind(Value, Field, AddressBook) of
#contact{fname = Fname, lname = Lname} ->
{Fname, Lname};
false ->
{error, not_found}
end.
fields() ->
Fields = record_info(fields, contact),
ok = io:format("Fields: ~tp~n", [Fields]).
ceverett@REDACTED:~/Code/erlang$ erlc -E recfind.erl
ceverett@REDACTED:~/Code/erlang$ cat recfind.E
-file("recfind.erl", 1).
find_by_phone(Phone, AddressBook) ->
find(Phone, 4, AddressBook).
find_by_mail(Mail, AddressBook) ->
find(Mail, 5, AddressBook).
find(Value, Field, AddressBook) ->
case lists:keyfind(Value, Field, AddressBook) of
{contact,Fname,Lname,_,_,_,_} ->
{Fname,Lname};
false ->
{error,not_found}
end.
fields() ->
Fields = [fname,lname,phone,mail,city,street],
ok = io:format("Fields: ~tp~n", [Fields]).
module_info() ->
erlang:get_module_info(recfind).
module_info(X) ->
erlang:get_module_info(recfind, X).
=====================================================================
You see what happened in the function fields/0?
Fields = record_info(fields, contact),
became
Fields = [fname,lname,phone,mail,city,street],
and
find(Mail, #contact.mail, AddressBook)
became
find(Phone, 4, AddressBook).
and
#contact{fname = Fname, lname = Lname}
became
{contact,Fname,Lname,_,_,_,_}
So, the basic answer to your question is "no". But the more interesting answer is to ask you another question: What is the effect you are trying to achieve by using record_info/2 at runtime? Maybe a different data structure is better, maybe the #record.accessor syntax is sufficient, and maybe what you are trying to do can be done better some other way?
-Craig
More information about the erlang-questions
mailing list