Erlang中的record与宏
http://www.cnblogs.com/me-sa/archive/2011/07/20/erlang0006.html
在Erlang中使用Tuple ,数据项的顺序\数量都是确定的,一旦数据项顺序调整或者增减字段,都容易出现badmatch.
同时一些常量如果硬编码到代码中,一旦数值变化,要想全部可靠的替换成新的数值是一个困难的事情.
这两种数据层面的变化,在Erlang中对应的解决方案是: record Macro
在代码中我们创建一个record: -record(man , { name , age=0, school}).
2012-6-13 16:11:04更新
注意下面的代码都是从erl文件中截取的代码片段,如果要在Erlang Shell中使用record,参见:[Erlang 0027] Using Record in Erlang Shell
我们通过下面的代码看看对应字段的默认值:
%See default value
M=#man{},
io:format("M is : ~p ~n", [ M ]),
可以看到输出M的值是:{man,undefined,0,undefined},其实从这里我们就可以看到record在Erlang的内部实现是还是一个tuple.
从纯数据的角度我们发现{man,undefined,0,undefined}==M ,但record本身作为一种数据抽象机制,我们不要直接record的tuple值形式.
我们给特定的字段赋值,再看:
输出是 M2 is : {man,"zen",23,"No.14"}
以M2数据为模板,可以生成新的record:
结果是: M3 is : {man,"tt",24,"No.14"}
也可以这样使用数据模板:
2012-10-15 14:39:43更新
有一个record的list,其字段是a,b,c,例如{user,a,b,c},现在想利用它的list生成另外一个record的list,其字段是{user1,b,c},怎么写最方便
user1就是比user少了一个字段而已
坚强☆2002 14:39:00

Eshell V5.9 (abort with ^G)
1> rd(u1,{a,b,c}).
u1
2> rd(u2,{b,c}).
u2
3> Users=[#u1{a=12,b="ligaoren",c=true},#u1{a=23,b="zen",c=false}].
[#u1{a = 12,b = "ligaoren",c = true},
#u1{a = 23,b = "zen",c = false}]
4> [begin #u1{b=B,c=C}=U, #u2{b=B,c=C} end|| U<-Users].
[#u2{b = "ligaoren",c = true},#u2{b = "zen",c = false}]
5>

下面的例子演示如何取值:
结果是: M4 is : {man,"tt2",24,undefined}
我们尝试嵌套一个record到man,我们把name字段扩展一下:
-record(name ,{firstname,lastname}).
我们使用M2作为数据模板来生成M5,同时尝试取firstname的值:
io:format("M5 firstname is : ~p ~n ", [ M5#man.name#name.firstname ])
在Erlang中匹配无处不在,在使用record的时候我们可以通过匹配的方式提取某些字段的值:
比如这个方法:
show2(#man{name =Name ,age =Age } = M ) when is_record(M , man) ->
io:format("Name : ~p Age: ~p ~n ", [ Name ,Age ]).
这个方法在入口的位置就提取出来了Name和Age,注意这里只有M是record man,所以我们增加了一个Guard:is_record(M , man)
上面是关于record的一些常规操作,我会有一些疑问:在实际使用record中我们会常遇到badrecord的错误,这个错误erlang是怎么判断的?
同样的is_record 是怎么判断的?要想知道这个答案就需要重新编译我们的测试文件,添加编译选项,在Erlang Shell中使用下面的方法:
c(test,['E']).这样在同一目录里面就会生成一个test.E文件,打开这个文件,一切豁然开朗,我们以 M3 = M2#man{name="tt", age=24},
io:format("M3 is : ~p ~n ", [ M3 ]),这句为例,编译出来的代码是:

M3 =
begin
rec1 = M2,
case rec1 of
{man,rec2,rec3,rec4} -> %是通过匹配Tuple的方式进行的判断
{man,"tt",24,rec4};
_ ->
error({badrecord,man})
end
end,
io:format("M3 is : ~p ~n ", [M3]),

再看看刚刚那段生成 show2生成的对应代码:
这里有一个匹配取值的,会影响我们阅读,我们简化一下:
它编译出来的代码是:
show({man,_,_,_} = M) when true ->
io:format("show M : ~p ~n ", [M]).
很难想象如果没有宏,我们的Erlang代码要多么的难读,到处都是Magic Number;简单总结一下Erlang中宏的用法:
- 常量宏 比如-define(TIMEOUT, 1000). -define(ServerName,my_first_game_server ).
- 带参宏 比如: -define(Eq(X,Y),X=:=Y).
-define(P(Content),ok). - 条件宏
-ifdef(product).
-define(Who,"product_db_adm").
-else.
-define(Who,"test_db_adm").
-endif. - 全局宏: ?MACHINE (VM 名称)
?LINE 当前代码行
?FILE 当前代码文件
还有最熟悉的?MODULE 当前模块
还有一个比较常用在输出调试信息的宏:
-define(VALUE(Call),io:format("~p = ~p~n",[??Call,Call])).
test1() -> ?VALUE(length([1,2,3])).2012-07-16更新
- {d,Macro}{d,Macro,Value}
Defines a macro Macro to have the value Value. The default is true.
Example:

-module(m).
... -ifdef(debug).
-define(LOG(X), io:format("{~p,~p}: ~p~n", [?MODULE,?LINE,X])).
-else.
-define(LOG(X), true).
-endif. ...
When trace output is desired, debug should be defined when the module m is compiled:
% erlc -Ddebug m.erl or 1> c(m, {d, debug}).
{ok,m}
条件宏可以通过编译选项的方式,切换是生产环境的版本还是debug的版本,生产环境要屏蔽掉debug输出就可以轻松实现了;
按照同样的方法我们可以看一下Macro,只需要把编译的时候使用c(test,['P']).下面就是一个使用宏的例子,猜猜它被编译之后是什么样子?
-module(mac).
-export([dump/1,go/1,show/2,len/1,say/0]).
-define(Func,X).
-define(Double,*2).
-define(F,dump(X)).
-define(Eq(X,Y),X=:=Y).
%-define(P(Content),ok).
-define(PF(Content,Args),io:format(Content,Args)).
-define(P(Content),io:format(Content)).
-define(Len(Call),io:format("~p=~p ~n",[??Call,Call])).
-ifdef(me).
-define(Who,"abcd").
-else.
-define(Who,"zen").
-endif.
say()->
?P(?Who).
len(List) when is_list(List) ->
?Len(length(List)).
dump(X)->
?Func?Double.
go(X)->
?F.
show(X,Y) when ?Eq(X,Y)->
?P("They are Equal. ~n");
show(_X,_Y)->
io:format("HAHA").

-module(mac). -export([dump/1,go/1,show/2,len/1,say/0]). -define(Func,X).
-define(Double,*2).
-define(F,dump(X)).
-define(Eq(X,Y),X=:=Y).
%-define(P(Content),ok).
-define(PF(Content,Args),io:format(Content,Args)).
-define(P(Content),io:format(Content)). -define(Len(Call),io:format("~p=~p ~n",[??Call,Call])). -ifdef(me).
-define(Who,"abcd").
-else.
-define(Who,"zen").
-endif. say()->
?P(?Who). len(List) when is_list(List) ->
?Len(length(List)). dump(X)->
?Func?Double. go(X)->
?F. show(X,Y) when ?Eq(X,Y)->
?P("They are Equal. ~n");
show(_X,_Y)->
io:format("HAHA").

生成的P文件在这里:
-file("./mac.erl", 1).
-module(mac).
-export([dump/1,go/1,show/2,len/1,say/0]).
say() ->
io:format("zen").
len(List) when is_list(List) ->
io:format("~p=~p ~n", ["length ( List )",length(List)]).
dump(X) ->
X * 2.
go(X) ->
dump(X).
show(X, Y) when X =:= Y ->
io:format("They are Equal. ~n");
show(_X, _Y) ->
io:format("HAHA").

-file("./mac.erl", 1).
-module(mac).
-export([dump/1,go/1,show/2,len/1,say/0]).
say() ->
io:format("zen").
len(List) when is_list(List) ->
io:format("~p=~p ~n", ["length ( List )",length(List)]).
dump(X) ->
X * 2.
go(X) ->
dump(X).
show(X, Y) when X =:= Y ->
io:format("They are Equal. ~n");
show(_X, _Y) ->
io:format("HAHA").

在项目中,这些record macro 往往被放在hrl文件中,通过Emakefile进行编译定制,这个之前我们讨论过不再赘述,点击这里查看;
Erlang中的record与宏的更多相关文章
- 代码中,使用__DATE__宏,获取程序编译时间,如何保证每次编译代码(非重新生成方式),都能更新__DATE__的值?
代码中,使用__DATE__宏,获取程序编译时间,如何保证每次编译代码(非重新生成方式),都能更新__DATE__的值? 解决:通过vs的预先生成命令中,添加批处理命令,删除对应的obj文件方式,强制 ...
- VC中预处理指令与宏定义详解
刚接触到MFC编程的人往往会被MFC 向导生成的各种宏定义和预处理指令所吓倒,但是预处理和宏定义又是C语言的一个强大工具.使用它们可以进行简单的源代码控制,版本控制,预警或者完成一些特殊的功能. 一个 ...
- C中的预编译宏定义
可以用宏判断是否为ARC环境 #if _has_feature(objc_arc) #else //MRC #endif C中的预编译宏定义 -- 作者: infobillows 来源:网络 在将一 ...
- C++ 中常见预定义宏的使用
http://blog.csdn.net/hgl868/article/details/7058906 替代字符串: #define DOWNLOAD_IMAGE_LOG /var/log/png.l ...
- uboot中的中断macro宏
目录 uboot中的中断macro宏 引入 内存分配 流程概览 普通中断 保存现场 中断函数打印具体寄存器 恢复现场 软中断 空间获取 保存现场 附录速记 疑惑待解 title: uboot中的中断m ...
- Erlang中一些错误或者异常的标识
erlang中错误大体分为四种: 1. 编译错误 2. 逻辑错误 3. 运行时错误 4. 用户代码生成的错误 编译错误,主要是编译器检测出的代码语法错误 逻辑错误,是指程序没有完成预 ...
- visual c++中预定义的宏
一.主要目标 (由于visual studio通常包含很多开发环境,通常将其中c/c++的ide称为visual c++ 20xx) 整理下visual c++ 2010下预定义的宏.做一下备忘和了解 ...
- Erlang中atom的实现
Erlang的原子(atom)在匹配中有着重要作用,它兼顾了可读性和运行效率. 通过atom,可以实现很多灵活高效的应用. atom可以看作是给字符串生成了一个ID,内部使用的是ID值,必要时可以取出 ...
- [erlang 001] erlang中的错误及异常处理
一. erlang中的错误 1. 分类 1) 编译错误:主要是编译器检测出的代码语法错误: 2) 逻辑错误:是指程序没有完成预期的工作,属于开发人员的问题: 3) 运行时错误:是指erlang运行时抛 ...
随机推荐
- Android 开发之锁屏弹窗
尝试利用 WindowManager 添加浮窗的方式实现 想在锁屏上面实现弹窗,第一个想法就是利用 WindowManager 设置 Window 的 Flag,通过设置 Flag 的显示优先级来让窗 ...
- ORACLE10g R2【RAC+ASM→RAC+ASM】
ORACLE10g R2[RAC+ASM→RAC+ASM] 本演示案例所用环境:RAC+ASM+OMF primary standby OS Hostname node1,node2 dgnode ...
- QQ群功能设计与心理学
刚刚在一个Java技术交流群,发了个 "博客投票"的广告. 群主两眼一黑,瞬间就把我给干掉了. 看到QQ给出的系统消息,发现QQ群的一个功能做得很不错. 大家注意到,右边有个&qu ...
- 【例 7-12 UVA - 1343】The Rotation Game
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 迭代加深搜索. 每次抽动操作最多只会让中间那一块的区域离目标的"距离"减少1. 以这个作为剪枝. 枚举最大深度. ...
- Android应用开发-小巫CSDN博客client之获取评论列表
Android应用开发-小巫CSDN博客客户端之获取评论列表 上一篇博客介绍了博文具体内容的业务逻辑实现,本篇博客介绍小巫CSDN博客客户端的最后一项功能.获取评论列表,这个功能的实现跟前面获取文章列 ...
- amazeui学习笔记--css(常用组件13)--进度条Progress
amazeui学习笔记--css(常用组件13)--进度条Progress 一.总结 1.进度条基本使用:进度条组件,.am-progress 为容器,.am-progress-bar 为进度显示信息 ...
- Lucy_Hedgehog techniques
在project euler 的第\(10\)题的 \(forum\) 中 Lucy Hedgehog 提到的这种方法. 求 \(n\) 以内素数个数以及求 \(n\) 以内素数和的算法. 定义\(S ...
- net基础题
1. 简述 private. protected. public. internal 修饰符的访问权限. 答 . private : 私有成员, 在类的内部才可以访问. protected : 保 ...
- Centos minimal 安装桌面
yum update yum groupinstall -y 'X Window System' yum groupinstall -y 'Desktop' #中文支持 yum groupinstal ...
- 系统学习java高并发系列一
转载请注明原创出处,谢谢! JAVA服务端或者后端需要大量的高并发计算,所以高并发在JAVA服务端或者后端编程中显的格外重要了. 首先需要有几个概念: 1.同步和异步 同步异步是来形容方法的一次调用的 ...