http://www.cnblogs.com/me-sa/archive/2011/07/20/erlang0006.html

在Erlang中使用Tuple ,数据项的顺序\数量都是确定的,一旦数据项顺序调整或者增减字段,都容易出现badmatch.

同时一些常量如果硬编码到代码中,一旦数值变化,要想全部可靠的替换成新的数值是一个困难的事情.

这两种数据层面的变化,在Erlang中对应的解决方案是: record  Macro

record  

在代码中我们创建一个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=#man{name="zen", age=23, school = "No.14"},
     io:format("M2  is : ~p   ~n", [ M2 ]),

输出是  M2  is : {man,"zen",23,"No.14"}

以M2数据为模板,可以生成新的record:

     M3 = M2#man{name="tt", age=24},
      io:format("M3  is : ~p  ~n ", [ M3 ]),

结果是: M3  is : {man,"tt",24,"No.14"}

也可以这样使用数据模板:

 birthday(M) when is_record(M,man ) ->
     M#man{age=M#man.age +1}.             

2012-10-15 14:39:43更新

 博客园-海滩  14:07:08
有一个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 = #man{name="tt2", age=M3#man.age},
      io:format("M4  is : ~p ~n ", [ M4 ]),

结果是: M4  is : {man,"tt2",24,undefined}

我们尝试嵌套一个record到man,我们把name字段扩展一下:

-record(name ,{firstname,lastname}).

我们使用M2作为数据模板来生成M5,同时尝试取firstname的值:

   M5 =M2#man{name=#name{firstname="K",lastname="J"},age=24},
   io:format("M5  is : ~p ~n ", [ M5 ]),

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生成的对应代码:

show2({man,Name,Age,_} = {man,_,_,_} = M) when true ->
    io:format("Name   : ~p  Age: ~p  ~n ", [Name,Age]).

这里有一个匹配取值的,会影响我们阅读,我们简化一下:

 show( M ) when is_record(M , man) -> 
        io:format("show M   : ~p ~n ", [ M ]).

它编译出来的代码是:

show({man,_,_,_} = M) when true ->

io:format("show M   : ~p ~n ", [M]).

 
 
Macro
 

很难想象如果没有宏,我们的Erlang代码要多么的难读,到处都是Magic Number;简单总结一下Erlang中宏的用法:

  1. 常量宏 比如-define(TIMEOUT, 1000). -define(ServerName,my_first_game_server ).
  2. 带参宏 比如: -define(Eq(X,Y),X=:=Y).
    -define(P(Content),ok).
  3. 条件宏
    -ifdef(product).
        -define(Who,"product_db_adm").
    -else.
        -define(Who,"test_db_adm").
    -endif.
  4. 全局宏: ?MACHINE (VM 名称) 
                ?LINE 当前代码行
                ?FILE 当前代码文件
    还有最熟悉的?MODULE 当前模块 
    还有一个比较常用在输出调试信息的宏:
    -define(VALUE(Call),io:format("~p = ~p~n",[??Call,Call])).
    test1() -> ?VALUE(length([1,2,3])).

    2012-07-16更新

  5. {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}

    官方文档地址: http://www.erlang.org/doc/man/compile.html

    http://www.erlang.org/doc/reference_manual/macros.html

条件宏可以通过编译选项的方式,切换是生产环境的版本还是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与宏的更多相关文章

  1. 代码中,使用__DATE__宏,获取程序编译时间,如何保证每次编译代码(非重新生成方式),都能更新__DATE__的值?

    代码中,使用__DATE__宏,获取程序编译时间,如何保证每次编译代码(非重新生成方式),都能更新__DATE__的值? 解决:通过vs的预先生成命令中,添加批处理命令,删除对应的obj文件方式,强制 ...

  2. VC中预处理指令与宏定义详解

    刚接触到MFC编程的人往往会被MFC 向导生成的各种宏定义和预处理指令所吓倒,但是预处理和宏定义又是C语言的一个强大工具.使用它们可以进行简单的源代码控制,版本控制,预警或者完成一些特殊的功能. 一个 ...

  3. C中的预编译宏定义

     可以用宏判断是否为ARC环境 #if _has_feature(objc_arc) #else //MRC #endif C中的预编译宏定义 -- 作者: infobillows 来源:网络 在将一 ...

  4. C++ 中常见预定义宏的使用

    http://blog.csdn.net/hgl868/article/details/7058906 替代字符串: #define DOWNLOAD_IMAGE_LOG /var/log/png.l ...

  5. uboot中的中断macro宏

    目录 uboot中的中断macro宏 引入 内存分配 流程概览 普通中断 保存现场 中断函数打印具体寄存器 恢复现场 软中断 空间获取 保存现场 附录速记 疑惑待解 title: uboot中的中断m ...

  6. Erlang中一些错误或者异常的标识

    erlang中错误大体分为四种: 1. 编译错误    2. 逻辑错误    3. 运行时错误    4. 用户代码生成的错误 编译错误,主要是编译器检测出的代码语法错误 逻辑错误,是指程序没有完成预 ...

  7. visual c++中预定义的宏

    一.主要目标 (由于visual studio通常包含很多开发环境,通常将其中c/c++的ide称为visual c++ 20xx) 整理下visual c++ 2010下预定义的宏.做一下备忘和了解 ...

  8. Erlang中atom的实现

    Erlang的原子(atom)在匹配中有着重要作用,它兼顾了可读性和运行效率. 通过atom,可以实现很多灵活高效的应用. atom可以看作是给字符串生成了一个ID,内部使用的是ID值,必要时可以取出 ...

  9. [erlang 001] erlang中的错误及异常处理

    一. erlang中的错误 1. 分类 1) 编译错误:主要是编译器检测出的代码语法错误: 2) 逻辑错误:是指程序没有完成预期的工作,属于开发人员的问题: 3) 运行时错误:是指erlang运行时抛 ...

随机推荐

  1. HTML基础第九讲---表单

    转自:https://i.cnblogs.com/posts?categoryid=1121494 最基本的留言版应该大家都用过吧!没错这就是一个表单运用很好的例子.表单提供了一个管道让读者发表心声, ...

  2. 每日技术总结:fly.js,个位数前补零等

    01.FLY.JS 文档:https://wendux.github.io/dist/#/doc/flyio/readme 02.微信小程序组件——input属性之cursor-spacing 属性 ...

  3. BAT面试题 - 找一个无序实数数组中的最大差值

    题目描写叙述: 一个无序的实数数组a[i].要求求里面大小相邻的实数的差的最大值.比方 double a[]={1,5,4,0.2,100} 这个无序的数组,相邻的数的最大差值为100-5=95. 题 ...

  4. Java Timer TimerTask Example(java Timer的例子)

    Java java.util.Timer is a utility class that can be used to schedule a thread to be executed at cert ...

  5. HDU 1018 Big Number 数学题解

    Problem Description In many applications very large integers numbers are required. Some of these app ...

  6. Leetcode之Best Time to Buy and Sell Stock

    Say you have an array for which the ith element is the price of a given stock on day i. If you were ...

  7. c++11 多线程 -- 基本使用

    c++11 多线程 – 基本使用 前言:这篇文章仅针对没有使用过c++11线程库的童鞋来高速入门,也是自己的一个简单记录,内容比較基础. 1.线程的基本使用 2.相互排斥量 3.条件变量 4.原子变量 ...

  8. (转)SQL Server 2012笔记分享-25:配置备份维护计划

    本文转自http://543925535.blog.51cto.com/639838/1427529 在日常的SQL维护中,有很多需要重复周期性去做的工作我们不太可能去手动操作完成,比如备份作业.重建 ...

  9. DSO Framer _ WinForm 使用

    根据自己对dsoframer控件的学习,想把dsoframer控件进行简单的包装为C#的usercontrol,大体需要作如下:(创建windows的usercontrol的步骤就不再说了...)我们 ...

  10. Windows平台CUDA开发之前的准备工作

    CUDA是NVIDIA的GPU开发工具,眼下在大规模并行计算领域有着广泛应用. windows平台上面的CUDA开发之前.最好去NVIDIA官网查看说明,然后下载对应的driver. ToolKits ...