[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


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

目录
相关文章
|
Web App开发 Shell Linux
|
2月前
|
Shell
一个用于添加/删除定时任务的shell脚本
一个用于添加/删除定时任务的shell脚本
110 1
|
1月前
|
Shell Linux 测试技术
6种方法打造出色的Shell脚本
6种方法打造出色的Shell脚本
62 2
6种方法打造出色的Shell脚本
|
1月前
|
XML JSON 监控
Shell脚本要点和难点以及具体应用和优缺点介绍
Shell脚本在系统管理和自动化任务中扮演着重要角色。尽管存在调试困难、可读性差等问题,但其简洁高效、易于学习和强大的功能使其在许多场景中不可或缺。通过掌握Shell脚本的基本语法、常用命令和函数,并了解其优缺点,开发者可以编写出高效的脚本来完成各种任务,提高工作效率。希望本文能为您在Shell脚本编写和应用中提供有价值的参考和指导。
58 1