使用Erlang交互式shell方便测试代码和程序,但是当我们需要编写大量代码且后续仍需Code时,肯定我们需要将Code保存到某个文件中。这就引入了模块(module)的概念。
模块(module)
如果有过编程经验的,我们就不会对模块的概念感到陌生。其实Erlang中的模块跟其他编程语言(Java,Python,C...)相差无几.
模块是Erlang中代码的基本单元,我们所编写的代码都存在于模块之中。模块文件通常存放在以.erl为扩展名的文件中。
创建模块
IOW,所谓的“创建模块”其实也就是新建一个后缀名为erl的源文件。
编写模块时,可以定义2种东西:函数(function) 和属性(attribute)
属性(Attribute):
属性是元数据,用来描述模块自身。如模块的名字,外部可见的函数、模块的作者等...
所有模块属性都采用-Name(Attribute).的形式。
模块中的有一个必须定义的属性,且永远都是文件的第一个属性(第一条语句)。即 -module(ModuleName).
ModuleName是一个原子。
函数调用的形式是M:F(A),其中M是模块名,F是函数名,A是函数参数。
-module属性中定义的模块名和模块文件的名字必须一致。
当模块文件中有-module(ModuleName). 这一句是就是合法的模块,但是如果没有任何函数,该模块 便毫无用处。
那我们开始定义函数。
定义函数
函数定义的语法遵循 Name(Args) -> Body. 这样的形式
Name 必须是一个原子,
Body 必须可以是一个or多个用逗号分隔的Erlang表达式。
函数以句号(.)结束。
函数中最后一个表达式的执行结果会被自动作为返回值传递给调用者(Erlang 中没有return 关键字)。
%% Erlang中的函数定义
add(X,Y) ->
X+Y.
现在模块有了属性&函数,应该可以使用了吧?
此时我不得不佩服Erlang的发明者的高瞻远瞩和精妙设计,因为它在这里考虑到了函数的访问权限问题。而且不像Java那样使用访问修饰符达到目的。下面我们来引入第二个重要的属性 -export.
export属性
- export属性定义的一般形式:
-export([Func1/Arity,Func2/Arity,...,FuncN/Arity]).
export属性用来定义模块中的哪些函数可以被其他模块调用,它接收一个带有各自元数(arity)的函数名列表。函数的元数是个整数,表示该函数可以接收的参数个数。这个arity很重要,因为在同一模块中定义两个同名的函数,只要arity个数不同,那就是不同的函数。(避免我们抓耳挠腮,冥思苦想地去给函数想个新名字)。
注意:导出的函数就相当于模块的接口。
在定义接口时,尽量只暴露使用这个模块所必需的最少的信息。
import 属性
- import属性定义的一般形式:
-import (Module,[Func1/Arity,...,FuncN/Arity).
因为引入函数的做法会降低代码的可读性,所以大多数程序猿都强烈反对在代码中使用-import属性,尽管有时它确实方便。
来看一下情况:
io:format/2有一个同名函数,不过在另一个库io_lib:format/2中。如果函数被引入,那么我们要想判断代码中使用的到底是哪个模块的函数,就have to 跑到文件最前面看-import属性。
强烈建议:在函数调用中包含模块名,但不绝对。
Erlang的注释
在Erlang中,注释都是单行的,以%符号起始...
在Erlang社区中,习惯:
- 模块的概括性注释以及模块的区段分隔注释(公有代码,私有代码,辅助函数等)中使用3个百分号(%%%);
- 在所有其他需要放置在独立行的注释使用2个百分号(%%),并和周边的代码采用同样的缩进;
- 放在代码之后的行内注释,使用单个%;
代码示例:
%%% first.erl
%%% 定义一个名为first的模块文件
-module(first). % 必需属性,必须写在第一行,()里必须和模块文件的名字相同
-export([sayHello(1),add/2]). % 导出的函数
%% 输出欢迎语
%% io:format /1 是标准的文本输出函数
sayHello(Name) ->
io:format("Hello, -s -n",[Name]). % 注意这里的Name要用[]括起来
%% 加法操作
add(X,Y) ->
X + Y.
我们知道静态语言都要经历编译,执行的过程,现在我们可以创建出源代码了,那么下一步操作就是编译执行环节啦。
如果有需要Erlang相关书籍(PDF)的仁人志士,请下方评论即可
免费赠送...
免费赠送...
免费赠送...