[Erlang 0027] Using Record in Erlang Shell-阿里云开发者社区

开发者社区> 开发与运维> 正文

[Erlang 0027] Using Record in Erlang Shell

简介:

     [Erlang 0006] Erlang中的record与宏 中我们提到过Record是一个编译时的功能,在Erlang VM中并没有专门的数据类型.在线上解决问题有时候会遇到要在shell中使用record,那么就有两个选择:1.在shell中构造record定义,如果能构造record有了record的定义编写ets:match的匹配模式就方便多了; 2.直接使用record对应的tuple结构;

方法一 使用rd命令

复制代码
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}
复制代码



方法二使用rr命令
rr命令可以加载模块中的record定义,我们把record放在一个模块中:

-module(records).
-record(book,{name, id, item01, item02, item03, item04, item05, item06, item07, item08, item09, item10 } ).
-record(film ,{ director, actor, type, name,imdb}).

注意:rr方法是支持通配符的,比如rr("*")


我们在shell中编译并尝试加载其中的record:

复制代码
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>
复制代码

 

方法三 最方便的方案 user_default

上面两种方法一种是手工定义,一种是手工加载定义,有更理想的方案么?有!
仔细阅读一下Erlang shell的文档,我们可以看到下面这段: 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.

我们就使用user_default来解决这个问题!!!我们准备一下测试的文件:

复制代码
%% 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.
复制代码

编译一下user_default.erl,编译之后我们启动Erlang Shell,可以看到不仅record已经加载了,而且user_default中定义的方法也可以直接访问.

复制代码
Eshell V5.9 (abort with ^G)
1> rl(). %% 在shell中可以使用rl()查看已经定义的record.
-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}).
ok
2> get_timestamp().
1325308014
3> F=foo#{}.
* 1: syntax error before: '{'
3> F=#foo{}.
#foo{id = undefined,name = undefined,bar = undefined}
4>
复制代码

 

补遗:

在centos环境,在user_default.beam所在的目录启动erl 使用rl()查看,record定义没有加载,只返回了ok

我怀疑是user_default的加载时机有问题,就修改了~/.erlang 文件,添加了加载逻辑 code:load_abs("/data/op_server/user_default").
这样修改之后,还是没有效果,然后我怀疑是不是~/.erlang文件没有执行;于是我故意把里面的代码改错,再启动erl报错,这样可以确认这个文件的内容确实执行了

立涛的回答:
code:load_abs("..../user_default").
这一行删除也没有关系。
只要HOME目录下有user_default.beam

 

 成立涛  19:53:36
编译的时候加上erlc +debug_info user_default.erl
然后把user_default.beam放到当前目录就ok了。
我看了下代码 :) 

 

 

方法四 不定义直接使用tuple
[Erlang 0006] Erlang中的record与宏 我们说过record在Erlang的内部实现是还是一个tuple.在shell中我们可以使用等效的tuple.
4> F2 =#film{director=2012}.
#film{director = 2012,actor = undefined,type = undefined,
name = undefined,imdb = undefined}
5> F2 == {film , 2012, undefined, undefined, undefined, undefined} .
true

方法五 Match Specifications And Records (Dynamically!)
这是trapexit上提供的一个解决方案,稍微绕一点,主要是{ok,Tree}=epp:parse_file("myheader.hrl",["./"],[])解析头文件进行预处理,然后生成reocrd的元数据module文件,再利用工具类来动态生成match specification;

预处理模块的代码

详情点击这里: http://www.trapexit.org/Match_Specifications_And_Records_%28Dynamically%21%29


一个简单的问题,只要愿意去想,答案不止一个;

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章