Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>It sounds like you want to be able to do something like <code>get_record_field(Field, SomeRecord)</code> where <code>Field</code> is determined at runtime by user interface code say.</p> <p>You're right in that you can't do this in standard erlang as records and the <code>record_info</code> function are expanded and eliminated at compile time.</p> <p>There are a couple of solutions that I've used or looked at. My solution is as follows: (the example gives runtime access to the <code>#dns_rec</code> and <code>#dns_rr</code> records from <code>inet_dns.hrl</code>)</p> <pre><code>%% Retrieves the value stored in the record Rec in field Field. info(Field, Rec) -&gt; Fields = fields(Rec), info(Field, Fields, tl(tuple_to_list(Rec))). info(_Field, _Fields, []) -&gt; erlang:error(bad_record); info(_Field, [], _Rec) -&gt; erlang:error(bad_field); info(Field, [Field | _], [Val | _]) -&gt; Val; info(Field, [_Other | Fields], [_Val | Values]) -&gt; 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{}) -&gt; fields(dns_rec); fields(dns_rec) -&gt; record_info(fields, dns_rec); fields(#dns_rr{}) -&gt; fields(dns_rr); fields(dns_rr) -&gt; record_info(fields, dns_rr). %% Turns a record into a proplist suitable for use with the proplists module. to_proplist(R) -&gt; Keys = fields(R), Values = tl(tuple_to_list(R)), lists:zip(Keys,Values). </code></pre> <p>A version of this that compiles is available here: <a href="http://gist.github.com/71050" rel="nofollow noreferrer">rec_test.erl</a></p> <hr> <p>You can also extend this dynamic field lookup to dynamic generation of matchspecs for use with <code>ets:select/2</code> or <code>mnesia:select/2</code> as shown below:</p> <pre><code>%% Generates a matchspec that does something like this %% QLC psuedocode: [ V || #RecordKind{MatchField=V} &lt;- mnesia:table(RecordKind) ] match(MatchField, RecordKind) -&gt; MatchTuple = match_tuple(MatchField, RecordKind), {MatchTuple, [], ['$1']}. %% Generates a matchspec that does something like this %% QLC psuedocode: [ T || T &lt;- mnesia:table(RecordKind), %% T#RecordKind.Field =:= MatchValue] match(MatchField, MatchValue, RecordKind) -&gt; MatchTuple = match_tuple(MatchField, RecordKind), {MatchTuple, [{'=:=', '$1', MatchValue}], ['$$']}. %% Generates a matchspec that does something like this %% QLC psuedocode: [ T#RecordKind.ReturnField %% || T &lt;- mnesia:table(RecordKind), %% T#RecordKind.MatchField =:= MatchValue] match(MatchField, MatchValue, RecordKind, ReturnField) when MatchField =/= ReturnField -&gt; MatchTuple = list_to_tuple([RecordKind | [if F =:= MatchField -&gt; '$1'; F =:= ReturnField -&gt; '$2'; true -&gt; '_' end || F &lt;- fields(RecordKind)]]), {MatchTuple, [{'=:=', '$1', MatchValue}], ['$2']}. match_tuple(MatchField, RecordKind) -&gt; list_to_tuple([RecordKind | [if F =:= MatchField -&gt; '$1'; true -&gt; '_' end || F &lt;- fields(RecordKind)]]). </code></pre> <hr> <p>Ulf Wiger has also written a parse_transform, <a href="http://forum.trapexit.org/viewtopic.php?p=21790" rel="nofollow noreferrer">Exprecs</a>, that more or less does this for you automagically. I've never tried it, but Ulf's code is usually very good. </p> <hr>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload