• Erlang中的record与宏


    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进行编译定制,这个之前我们讨论过不再赘述,点击这里查看;    

  • 相关阅读:
    vector数组的翻转与排序
    20210310日报
    vector数组的遍历
    vector数组的删除
    vector数组的插入
    20210304日报
    20210303日报
    20210302日报
    计算datetime.date n个月后(前)的日期
    pandas 重命名MultiIndex列
  • 原文地址:https://www.cnblogs.com/fvsfvs123/p/4253414.html
Copyright © 2020-2023  润新知