[Erlang 0006] record and macro in Erlang we mentioned that record is a compilation function and there is no special data type in Erlang VM. if you want to solve the problem online and sometimes use record in shell, you have two options: 1. construct a record definition in shell. If a record can be constructed, it is much easier to compile the ETS: Match matching mode with the record definition. 2. directly use the tuple structure corresponding to the record;
Method 1 use the RD command
Eshell V5.9 (abort with ^G)
1> rd(film ,{ director, actor, type, name,imdb}).
film
2> F =#film{}.
#film{director = undefined,actor = undefined,
type = undefined,name = undefined,imdb = undefined}
3> F#film.type.
undefined
4> F#film.type=23.
* 1: illegal pattern
5> F2 =F#film{type=23}.
#film{director = undefined,actor = undefined,type = 23,
name = undefined,imdb = undefined}
Method 2 run the RR command
The RR command can load the record definition in the module. We put the record in a module:
-module(records).
-record(book,{name, id, item01, item02, item03, item04, item05, item06, item07, item08, item09, item10 } ).
-record(film ,{ director, actor, type, name,imdb}).
Note: The RR method supports wildcard characters, such as RR ("*")
We compile and try to load the record in the shell:
Eshell V5.9 (abort with ^G)
1> c(records).
records.erl:2: Warning: record book is unused
records.erl:19: Warning: record film is unused
{ok,records}
2> rr(records).
[book,film]
3> F =#film{}.
#film{director = undefined,actor = undefined,
type = undefined,name = undefined,imdb = undefined}
4>
Method 3 the most convenient solution user_default
The above two methods are manually defined, and the other is manually loaded. Is there a better solution? Yes!
Take a closer look at the Erlang shell documentation, we can see the following section: http://www.erlang.org/documentation/doc-5.4.12/lib/stdlib-1.13.11/doc/html/shell.html
If a command (local function call) is not recognized by the shell, an attempt is first made to find the function in the module user_default, where customized local commands can be placed. if found, then the function is evaluated. otherwise, an attempt is made to evaluate the function in the module shell_default. the module user_default must be explicitly loaded.
There is some support for reading and printing records in the shell. during compilation record expressions are translated to tuple expressions. in runtime it is not known whether a tuple actually represents a record. nor are the record definitions used by Compiler Available at runtime. so in order to read the record syntax and print tuples as records when possible, record definitions have to be maintained by the shell itself. the shell commands for reading, defining, forgetting, listing, and printing records are described below. note that each job has its own set of record definitions. to facilitate matters record definitions in the modules shell_default and user_default (if loaded) are read each time a new job is started.
We will use user_default to solve this problem !!! Prepare the test file:
%% File: records.hrl
-record(book,{ name, id, item01, item02, item03, item04, item05, item06, item07, item08, item09, item10 } ).
-record(film ,{ director, actor, type, name,imdb}).
-record(foo,{ id, name,bar}).
%% File: user_default.erl
-module(user_default).
-include("records.hrl").
-compile(export_all).
get_meta() ->
user_default:module_info().
get_timestamp() ->
{M, S, _} = erlang:now(),
M * 1000000 + S.
Compile user_default.erl. After compilation, we start Erlang shell. We can see that not only the record has been loaded, but also the methods defined in user_default can be directly accessed.
Eshell v5.9 (abort with ^ g)
1> RL (). % in shell, you can use RL () to view the defined record.
-Record (book, {name, ID, item01, item02, item03, item04, item05, item06, item07, item08, item09, item10 }).
-Record (film, {ctor, actor, type, name, IMDB }).
-Record (Foo, {ID, name, bar }).
OK
2> get_timestamp ().
1325308014
3> F = Foo #{}.
* 1: syntax error before :'{'
3> F = # Foo {}.
# Foo {id = undefined, name = undefined, bar = undefined}
4>
Addendum:
In the centos environment, start ERL to use RL () in the directory where user_default.beam is located. If the record definition is not loaded, only OK is returned.
I suspect there is a problem with the loading time of user_default, So I modified it ~ /. Erlang file, added the loading logic code: load_abs ("/data/op_server/user_default ").
After this modification, it still does not work, and I doubt if it is ~ The/. Erlang file is not executed, So I intentionally corrected the code in it and started ERL to report an error, so that I can confirm that the content of this file is indeed executed.
Li Tao's answer:
Code: load_abs (".../user_default ").
This row does not matter.
As long as the home directory contains user_default.beam
Cheng LiTaO 19:53:36
Add ERlC + debug_info user_default.erl during compilation
Then put user_default.beam in the current directory.
I read the code :)
Method 4: Use tuple directly without definition
[Erlang 0006] the record in Erlang is a tuple in Erlang. In Shell, we can use the equivalent tuple.
4> F2 = # film {Director = 2012 }.
# Film {Director = 2012, actor = undefined, type = undefined,
Name = undefined, IMDB = undefined}
5> F2 =={ film, 2012, undefined, undefined }.
True
Method 5 match specifications and records (dynamically !)
This is a solution provided on trapexit. It is a little bit backward, mainly {OK, tree} = EPP: parse_file ("myheader. HRL ",[". /"], []) parse the header file for preprocessing, then generate the reocrd Metadata module file, and use the tool class to dynamically generate the match specification;
Code of the preprocessing module
1 %%%-------------------------------------------------------------------
2 %%% File : record_util.erl
3 %%% Author : Gordon Guthrie gordon@hypernumbers.com
4 %%% Description : utilities for manipulating records
5 %%%
6 %%% Created : 2 Sep 2008 by Gordon Guthrie
7 %%%-------------------------------------------------------------------
8 -module(make_ms_util).
9
10 -include("myheader.hrl").
11
12 -export([make/0]).
13
14 -define(MODULENAME,"ms_util2").
15
16 make() ->
17 {ok,Tree}=epp:parse_file("myheader.hrl",["./"],[]),
18 Src=make_src(Tree),
19 ok=file:write_file(?MODULENAME++".erl",list_to_binary(Src)).
20
21 make_src(Tree) -> make_src(Tree,[]).
22
23 make_src([],Acc) -> make_src2(Acc,[],[]);
24 make_src([{attribute,_,record,Record}|T],Acc) -> make_src(T,[Record|Acc]);
25 make_src([_H|T],Acc) -> make_src(T,Acc).
26
27 make_src2([],Acc1,Acc2) -> top_and_tail(Acc1,Acc2);
28 make_src2([H|T],Acc1,Acc2) -> {NewAcc1,NewAcc2}=expand_rec(H),
29 make_src2(T,[NewAcc1|Acc1],[NewAcc2|Acc2]).
30
31 expand_rec({Name,Def}) -> expand_fields(Name,Def,1,[]).
32
33 expand_fields(Name,[],N,Acc) -> {mk2(Name,N-1),lists:reverse([mk(Name)|Acc])};
34 expand_fields(Name,[{record_field,_,{atom,_,F},_}|T],N,Acc) ->
35 expand_fields(Name,T,N+1,[mk(Name,F,N)|Acc]);
36 expand_fields(Name,[{record_field,_,{atom,_,F}}|T],N,Acc) ->
37 expand_fields(Name,T,N+1,[mk(Name,F,N)|Acc]);
38 expand_fields(Name,[H|T],N,Acc) -> expand_fields(Name,T,N+1,Acc).
39
40 %% mk2/1 builds the no of fields fns
41 mk2(Name,N) -> "no_of_fields("++atom_to_list(Name)++") -> "++
42 integer_to_list(N)++";\n".
43
44 %% mk/1 builds an error line
45 mk(Name) -> "get_index("++atom_to_list(Name)++",F) -> "++
46 "exit({error,\"Record: "++atom_to_list(Name)++
47 " has no field called \"++atom_to_list(F)});\n".
48
49 mk(Name,Field,N) ->
50 "get_index("++atom_to_list(Name)++","++
51 atom_to_list(Field)++")-> "++integer_to_list(N)++";\n".
52
53 top_and_tail(Acc1,Acc2)->
54 Top="%% This module automatically generated - do not edit\n"++
55 "\n"++
56 "%%% This module provides utilities for use in building\n"++
57 "%%% match specifications from records\n"++
58 "\n"++
59 "-module("++?MODULENAME++").\n"++
60 "\n"++
61 "-export([get_index/2,no_of_fields/1]).\n"++
62 "\n",
63 Tail1="no_of_fields(Other) -> exit({error,\"Invalid Record Name: \""++
64 "++Other}).\n\n\n",
65 Tail2="get_index(Record,_Field) -> exit({error,\""++
66 "Invalid Record Name: \"++Record}).\n",
67 Top++lists:flatten(Acc1)++Tail1++lists:flatten(Acc2)++Tail2.
Click here for details: http://www.trapexit.org/Match_Specifications_And_Records_%28Dynamically%21%29
There is more than one answer to a simple question as long as you are willing to think about it;