2010-06-02 第三章 顺序型编程
3.1 模块
- 模块是Erlang中代码的基本单元,函数都存于模块之中。模块文件通常存放在以.erl为扩展名的文件中。编译成功之后的模块文件其扩展名是.beam。
- 示例模块geometry.erl,如下所示:
-
(1)符号Name/N,即area/1,表示一个带有N个参数的名为Name的函数。N称为函数的运算目(arity)。
-
编译模块的命令:
-
area函数由若干个不同的子句构成,子句与子句之间用分号(;)分割。当调用这个函数时,对其调用参数的匹配过程从第一个子句开始依次向下进行
-
函数不能处理模式匹配失败的情形,此时程序会失败并抛出一个运行时的错误。
补充:代码要放在哪儿?
在编译程序之前,需要先把目录切换到存储代码所在的目录,例如模块geometry.erl存在目录C:/work下,则需要切换目录到C:/work。 Erlang Shell中有两个命令可以协助切换到正确的目录。(1)pwd()可以打印当前的工作目录。(2)cd(dir)则可以将当前目录切换到dir所在的目录。在Shell中应该使用正斜杠"/"来分隔目录名。例如:cd("c:/work").
小技巧:创建一个名为才C:/erl5.7.5/.erlang的文件(根据实际的安装路径进行调整),文件内容如下:
保存之后,每次启动Erlang时(启动Erlang标准发布版),它都能自动切换到目录c:/work。
3.3 同名不同目的函数
- 在Erlang中,同一个模块中的两个函数,如果他们同名但是目并不相同(即参数个数不同),这样的两个函数被认为是完全不相同的。
3.4 fun函数
- fun就是匿名函数。
- 能够返回fun或接受fun作为参数的函数,都被称为高阶函数(high-order function)。
- list是标准库中的一个模块,从中导出的很多函数都是以fun作为参数的。其中,(1) lists:map(F,L)函数将fun F应用到列表L中的每一个元素上,并返回一个新的列表。(2) lists:fileter(P,L)函数将返回一个新列表,新列表由列表L中每一个能满足P(E)为true的元素组成。
3.6 列表解析
- 列表解析式一种无须使用fun、map或filter来创建列表的表达式。例如lists:map(fun(X) -> 2*X end, L).等价于[2*X || X<- L].记号[ F(X) || X <- L]代表"由F(X)组成的列表,其中X是取值于列表L"。因此,[2*X || X<- L]意味着“列表L中每一个元素X乘以2后的列表”。
- 毕达哥拉斯三元组,是一个整数集合{A,B,C},它使得A2+B2=C2 。
3.7 算术表达式
- +X——加1,-X——减1,div——整除,rem——取余,bnot X——对X按位取反,X band Y——对X和Y安位取与,X bor Y——按位取或, X bxor Y——按位取异或, X bsl N——对X按位左移N位, X bsr N——按位右移N位。
3.8 断言
- 断言(guard)是一种用于强化模式匹配功能的结构。使用断言,可以在一个模式上做一些简单的变量测试和比较。可以在函数定义的头部使用断言,此时断言必须以关键字when开头,当然也可以在任何语言中允许使用表达式的地方使用断言。当断言用于表达式时,它们会被求值为一个原子true或者false。如果断言求值为true,则认为求值成功,否则就认为求值失败。
- 断言序列。断言序列可以是单个断言也可以是一系列用分号(;)分开的断言集合。在断言集合G1;G2;...Gn中,只要任何一个断言为true,则整个断言序列就为true。
- 断言也可以是一些用逗号分开的断言集合。断言几个GuardExpr1,GuardExpr2,...GuarExprN中,只有所有断言都为true,整个断言序列才为true。
- 断言不能使用用户定义的布尔表达式
- 断言表达式的合法的语法形式:
- 断言样例: 第一行表示T是具有6个元素的元组,且T的第3个元素的绝对值大于5。第2行表示X的第4个元素与列表L中的头元素相等。(将断言分开的逗号表示and与操作)。
3.9 记录
- 记录(record)提供了一种方法把一个名称与元组中的一个元素对应起来。
- 记录通过下面这种语法来定义:
- record不是一个shell命令(在shell中使用rr),记录的声明只能用于Erlang源代码而不能用于shell。
- 记录的定义可以包含在Erlang源代码或以.hrl为扩展名的文件中,这些文件可以被Erlang源代码引用。只有这种方法才能保证不同的Erlang模块使用同一个记录定义。
- shell中读取记录的定义:rr("record.hrl").
- 语法#todo{key1=Val1,...,KeyN=ValN}用于创建类型为todo的新纪录。key都是原子,而且必须和记录定义中的一样。若省略key,那么就使用记录定义中的默认值。
- 语法X1#todo{status=done}表示创建一个X1的副本(X1必须为todo类型),并将value值修改为done。这只是原记录的一个副本,原记录本身并未改变。
- 使用模式匹配从记录中提取字段值。也可以使用“点语法”。例如
- 在函数中对记录进行模式匹配
- 记录只是元组的伪装。