顺序编程
条件评估
有以下三种形式:
函数模式匹配
Example:
area2 ({circle,R}) -> math:pi()*R*R; area2 ({square,Side}) -> Side * Side; area2 (Other) -> {error,unknown_shape,Other}.
case 结构
表现形式:
case conditional-expression of Pattern1 -> expression1, expression2, .. ;, Pattern2 -> expression1, expression2, .. ; ... ; Patternn -> expression1, expression2, .. end
Example:
area (Shape) -> case Shape of {circle,R} -> math:pi()*R*R; {square,Side} -> Side * Side; Other -> {error,unknown_shape,Other} end.
Erlang不推荐防御性编程,这样屏蔽错误,不便于查找问题
if
Example:
area_if(Shape) -> {Type, R} = Shape, if Type == circle -> 3.14*R*R; Type == square -> R*R end.
保护元 guard
保护元是额外的限制条件,由 when 和保护元表达式组成。
保护元表达式可使用如下结构组成:
- 约束变量
- 常量的数据值,包括数字、基元、元组和列表等
- 类型测试语句,比如is_boolean等
- 比较运算符 == 、< 等
- 算数运算符
- 布尔表达式
- 保护元内置函数 (不允许使用用户自定义函数,避免边界效应)
保护元的逻辑组合:
- (,)分隔,等同于 and ,所有表达式都是true,结果为true。
- (;)分隔,等同于 or , 一个表达式或者(,)组成的表达式语句为true,结果为true。
example:
my_add2(x,y) when not(x>y), is_atom(x) ; not(is_atom(y)), x =/=3.4 ->
x+y.
推荐(,)和(;)不要混用,容易造成混淆,产生逻辑错误
内置函数
Erlang 社区中内置函数简写 BIF。 通常是C编写的,集成与VM中。erlang模块列出了标准和非标准的内置函数。(某些也在其他模块,比如ets和lists)
元编程
一个函数在运行时才确定调用哪些函数的特性叫做元编程。我们可以通过apply/3函数来实现。
% apply(Module, Function, Arguments)
M = erlang.
F = now.
apply(M,F,[]).
输入和输出
% 从标准输入读取一行
io:get_line("line>").
% 从标准输入读取指定数量的字符
io:get_chars("chars>",2).
% 从标准输入读取项元
io:read(">").
% >atom.
% {ok,atom}
% 输出项元
io:write/1
% 格式化输出
io:format/2
格式化控制序列:
控制序列 | 描述 |
---|---|
~c | 输出一个字符的ASCII码 |
~f | 输出一个有6个小数位的浮点数 |
~e | 输出一个以科学计数法表示的总共6位的浮点数 |
~w | 以标准语法输出任何项元 |
~p | 输出数据就如~w,但在“pretty printing”模式下,在适当地方换行和缩进,在可能的情况下把列表作为字符串输出 |
~P | 输出数据就如~w,~p,但限制结构深度为3.在数据列表中它有额外的一个参数来指明打印项元的最大深度 |
~B | 以10为基数输出一个整数 |
递归
% 递归
sum([]) -> 0;
sum([Head | Tail]) -> Head + sum(Tail).
% 尾递归 (函数调用发生在函数体的最后一个表达式)
sum_acc([],Sum) -> Sum;
sum_acc([Head | Tail],Sum) -> sum_acc(Tail, Head + Sum).
sum(List) -> sum_acc(List,0).
一般函数语言推荐尾递归,因为尾递归更节约内存,更效率。Erlang早期也是如此,但后来Erlang做过优化,已不能确定尾递归是否更有效率,除非在具体场景进行相应的性能测试。