十七:宏
-define(Constant,Replacement).
-define(Func(Varl,Var2,..,Var),Replacement).
-define(macrol(X,Y),{a,X,Y}).
fo0(A) ->
?macro1(A+10,b).
%% 它展开后是这样的:
f00(A) ->
{a,A+10,b}.
(1) ?FILE 展开成当前的文件名;(2) ?MODULE 展开成当前的模块名;(3) ?LINE 展开成当前的行号。
宏控制流
(1) -undef(Macro).
%% 取消宏的定义,此后就无法调用这个宏了。
(2) -ifdef(Macro)
%% 仅当Macro有过定义时才执行后面的代码。
(3) -ifndef(Macro).
%% 仅当Macro未被定义时才执行后面的代码。
(4) -else.
%% 可用于ifdef或ifndef语句之后。如果条件为否,else后面的语句就会被执行。
(5) -endif.
%% 标记ifdef或ifndef语句的结尾。
-ifdef (<FlagName>).
-define(...).
-else.
-define(...).
-endif.
%% m1.erl
-module(m1).
-export([loop/1]).
-ifdef(debug flag).
-define(DEBUG(X),io:format ("DEBUG ~p:~p ~p~n",[?MODULE,?LINE,X])).
-else.
-define(DEBUG(X),void).
-endif.
loop(0) ->
done;
loop(N) ->
?DEBUG(N),
1oop(N-1).
注:io:format(String, [Args]) 会根据String里的格式信息在Erlang shell中打印出 [Args] 所含的变量。格式编码用一个~符号作为前缀。~p是美化打印(pretty print)的简称,~n 则会生成一个新行。
1> c(m1,{d,debug_flag}).
{ok,m1}
2> m1:loop(4).
DEBUG m1:13 4
DEBUG m1:13 3
DEBUG m1:13 2
DEBUG ml:13 1
done
注:如果没有设置debug_flag,这个宏就只会展开成原子void。选择这个名称没有什么实际意义,只是用来提醒你没有人会对这个宏的值感兴趣。
十八:模式的匹配操作符
funcl([{tag1,A,B} | T])->
...
... f(..,{tagl,A,B},..)
...
func1([{tag1,A,B}=Z | T])->
...
...f(..., Z, ...)
...
func1([{tag,{one,A},B} | T])->
...
... f(..., {tag,{one,A}, B}, ...),
... g(..., {one,A}, ...)
...
funcl([{tag, {one,A}=Z1, B} = Z2 | T])->
...
... f(..., Z2, ...),
... g(..., Z1, ...),
...
总之来说,模式匹配操作符中的数据类型可以用变量表示。
十九:数字
整数
0 -65 2#010001110 -8#377 16#fe34 16#FE34 36#w0w
它们的值分别是0、-65、142、-255、65076、65076和42368。
浮点数
1.0 3.14159 -2.3e+6 23.56E-27
解析后的浮点数在系统内部使用IEEE 754的64位格式表示。绝对值在10-323到10308范围内的实数可以用Erlang的浮点数表示。
二十:操作符优先级
操作符 | 结合性 |
---|---|
: | |
# | |
(一元)+、(一元)-、bnot、not | |
/、*、 div、 rem、 band、 and | 左结合 |
+、-、bor、bxor、bsl、bsr、or、xor | 左结合 |
++、- - | 右结合 |
==、/=、=<、<、>=、>、==、=/= | |
andalso | |
orelse | |
=! | 右结合 |
catch |
二十一:进程字典
(1) put(Key,Value) -> OldValue.
%% 给进程字典添加一个Key, Value组合。put的值是OldValue,也就是Key之前关联的值。
%% 如果没有之前的值,就返回原子undefined。
(2) get(Key) -> Value.
%% 查找Key的值。如果字典里存在Key,Values组合就返回Value,否则返回原子undefined。
(3) get() -> [{Key,Value}].
%% 返回整个字典,形式是一个由{Key,Value}元组所构成的列表。
(4) get_keys(Value) -> [Key].
%% 返回一个列表,内含字典里所有值为Value的键。
(5) erase(Key) -> Value.
%% 返回Key的关联值,如果不存在则返回原子undefined。最后,删除Key的关联值。
(6) erase()->[[Key,Value}].
%% 删除整个进程字典。返回值是一个由{Key,Value}元组所构成的列表,代表了字典删除之前的状态。
实例:
1> erase().
[]
2> put(×,20).
undefined
3> get(x).
20
4> get(y).
undefined
5> put(y,40).
undefined
6> get(y).
40
7> get().
[{y,40},{×,20}]
8> erase(x).
20
9> get().
[{y,40}]
二十二:引用
二十三:短路布尔表达式
Exprl orelse Expr2
%% 它会首先执行Expr1。如果Expr1的执行结果是true,Expr2就不再执行。如果Expr1的执
%% 行结果是false,则会执行Expr2。
Expr1 andalso Expr2
%% 它会首先执行Expr1。如果Expr1的执行结果是true,则会执行Expr2。如果Expr1的执行
%% 结果是false,Expr2就不再执行。
注:在对应的布尔表达式里(A or B和A and B),两边的参数总会被执行,即使表达式的真值只需要第一个表达式的值就能确定也是如此。
二十四:比较数据类型
下表列出了全部可用的数据类型比较操作(八种):
操作符 | 含义 |
---|---|
X > Y | X大于Y |
X < Y | X小于Y |
X =< Y | X等于或小于Y |
X >= Y | X大于或等于Y |
X == Y | X等于Y |
X /= Y | X不等于Y |
X =:= Y | X与Y完全相同 |
X =/= Y | X与Y不完全相同 |
number < atom < reference < fun < port < pid < tuple (and record) < map < list < binary
(1) 如果一个参数是整数而另一个是浮点数,那么整数会先转换成浮点数,然后再进行比较。(2)如果两个参数都是整数或者都是浮点数,就会“按原样”使用,也就是不做转换。
二十五:元组模块
二十六:下划线变量
非常微妙的bug。举个例子,在一个非常复杂的模式匹配里,也许很难察觉_Int被多次不恰当地使用,从而导致模式匹配失败。
下划线变量主要有两种用途:
(1)命名一个我们不打算使用的变量。例如,相比open(File, _),open(File, _Mode)这种写法能让程序的可读性更高。
(2)用于调试。例如:
some func(X)->
{P,Q}=some_other_func(X),
io:format("Q = ~p ~n",[Q]),
P.
some func(X)->
{P,Q} = some_other_func(X),
%% io:format("Q = ~p ~n",[Q]),
P.
some func(X)->
{P,_Q}some_other_func(X),
%% io:format("_Q =-p-n",[_Q]),
P.
上面的注释中使用的_Q这种做法最好不要使用,这里使用只是表示该变量所用的地方注释掉后,就不会报变量Q未使用的警告。