5 模块
5.1 模块语法
Erlang 代码被划分为模块。一个模块包含一系列属性和函数声明,每个声明都以句点 (.) 结束。
示例
-module(m). % module attribute -export([fact/1]). % module attribute fact(N) when N>0 -> % beginning of function declaration N * fact(N-1); % | fact(0) -> % | 1. % end of function declaration
有关函数声明的描述,请参见 函数声明语法。
5.2 模块属性
模块属性定义了模块的特定属性。
模块属性包含一个标签和一个值
-Tag(Value).
Tag 必须是原子,而 Value 必须是文字项。作为对用户定义属性的方便操作,如果文字项 Value 的语法为 Name/Arity(其中 Name 是原子,Arity 是正整数),则项 Name/Arity 将被转换为 {Name,Arity}。
可以指定任何模块属性。这些属性存储在编译后的代码中,可以通过调用 Module:module_info(attributes) 或使用 STDLIB 中的模块 beam_lib(3) 来检索。
几个模块属性具有预定义的含义。其中一些属性的元数为二,但用户定义的模块属性的元数必须为一。
预定义模块属性
预定义模块属性应放在任何函数声明之前。
- -module(Module).
-
模块声明,定义模块的名称。名称 Module(一个原子)应与文件名减去扩展名 .erl 相同。否则,代码加载 无法按预期工作。
此属性应首先指定,并且是唯一必填属性。
- -export(Functions).
-
导出函数。指定模块内定义的哪些函数在模块外部可见。
Functions 是一个列表 [Name1/Arity1, ..., NameN/ArityN],其中每个 NameI 都是一个原子,ArityI 是一个整数。
- -import(Module,Functions).
-
导入函数。可以像本地函数一样调用,即无需任何模块前缀。
Module(一个原子)指定要从中导入函数的模块。 Functions 是与 export 相似的列表。
- -compile(Options).
-
编译器选项。 Options 是单个选项或选项列表。在编译模块时,此属性将添加到选项列表中。请参阅编译器中的 compile(3) 手册页。
- -vsn(Vsn).
-
模块版本。 Vsn 是任何文字项,可以使用 beam_lib:version/1 检索,请参阅 STDLIB 中的 beam_lib(3) 手册页。
如果没有指定此属性,则版本默认为模块的 MD5 校验和。
- -on_load(Function).
-
此属性命名一个函数,该函数将在模块加载时自动运行。有关更多信息,请参见 模块加载时运行函数。
- -nifs(Functions).
-
指定模块内定义的哪些函数可以作为 NIF 与 erlang:load_nif/2 一起加载。
Functions 是一个列表 [Name1/Arity1, ..., NameN/ArityN],其中每个 NameI 都是一个原子,ArityI 是一个整数。
虽然不是严格必要,但建议在任何加载 NIF 的模块中使用 -nifs() 属性,以允许编译器在优化方面做出更好的决策。
在不加载 NIF 的模块中,无需添加 -nifs([])。模块内没有任何对 erlang:load_nif/2 的调用就足以让编译器得出相同的结论。
更改-nifs() 属性的特殊含义是在 Erlang/OTP 25.0 中引入的。在之前的版本中,接受 -nifs(),但没有特殊含义。
行为模块属性
可以指定该模块是行为的回调模块
-behaviour(Behaviour).
原子 Behaviour 给出了行为的名称,它可以是用户定义的行为或以下 OTP 标准行为之一
- gen_server
- gen_statem
- gen_event
- supervisor
拼写 behavior 也被接受。
模块的回调函数可以通过导出的函数 behaviour_info/1 直接指定
behaviour_info(callbacks) -> Callbacks.
或者通过每个回调函数的 -callback 属性指定
-callback Name(Arguments) -> Result.
这里,Arguments 是零个或多个参数的列表。最好使用 -callback 属性,因为额外的类型信息可以被工具用来生成文档或查找差异。
在 OTP 设计原则 中阅读有关行为和回调模块的更多信息。
记录定义
记录定义使用与模块属性相同的语法
-record(Record,Fields).
记录定义允许在模块中的任何位置,包括函数声明中。在 记录 中阅读更多信息。
预处理器
预处理器使用与模块属性相同的语法,预处理器支持文件包含、宏和条件编译
-include("SomeFile.hrl"). -define(Macro,Replacement).
在 预处理器 中阅读更多信息。
设置文件和行
更改预定义宏 ?FILE 和 ?LINE 使用与模块属性相同的语法
-file(File, Line).
此属性被工具(如 Yecc)用来告知编译器源程序是由另一个工具生成的。它还指示源文件与原始用户编写文件的行的对应关系,原始用户编写文件产生源程序。
类型和函数规范
指定类型和函数规范使用与模块属性类似的语法
-type my_type() :: atom() | integer(). -spec my_function(integer()) -> integer().
在 类型和函数规范 中阅读更多信息。
该描述基于 EEP8 - 类型和函数规范,该规范不再更新。
5.3 feature 指令
虽然它不是模块属性,而是指令(因为它可能影响语法),但存在 -feature(..) 指令,用于启用和禁用 特性。
语法与属性类似,但有两个参数
-feature(FeatureName, enable | disable).
请注意,feature 指令 只能出现在模块的前缀中。
5.4 注释
注释可以放在模块中的任何位置,但不能放在字符串和引用的原子中。注释以字符 "%" 开头,一直延续到下一行结束处,但不包括下一行结束处,并且没有影响。请注意,终止行结束符的作用是空格。
5.5 module_info/0 和 module_info/1 函数
编译器会自动将两个特殊的导出函数插入到每个模块中
- Module:module_info/0
- Module:module_info/1
可以调用这些函数来检索有关模块的信息。
module_info/0
每个模块中的 module_info/0 函数返回一个包含有关模块信息的 {Key,Value} 元组列表。目前,该列表包含带有以下 Key 的元组:module、attributes、compile、exports、md5 和 native。元组的顺序和数量可能会在未经事先通知的情况下更改。
module_info/1
调用 module_info(Key),其中 Key 是一个原子,会返回有关模块的单个信息。
以下值允许用于 Key
- module
-
返回一个表示模块名称的原子。
- attributes
-
返回一个 {AttributeName,ValueList} 元组列表,其中 AttributeName 是属性的名称,而 ValueList 是一个值的列表。请注意,如果属性在模块中出现多次,则该属性可以在列表中出现多次,并具有不同的值。
如果模块使用 beam_lib(3) 模块(在 STDLIB 中)进行剥离,则属性列表将变为空。
- compile
-
返回一个包含有关模块编译方式信息的元组列表。如果模块使用 beam_lib(3) 模块(在 STDLIB 中)进行剥离,则此列表将为空。
- md5
-
返回表示模块 MD5 校验和的二进制数据。
- exports
-
返回一个 {Name,Arity} 元组列表,其中包含模块中所有导出的函数。
- functions
-
返回一个 {Name,Arity} 元组列表,其中包含模块中所有函数。
- nifs
-
返回一个 {Name,Arity} 元组列表,其中包含模块中所有 NIF 函数。
- native
-
如果模块具有原生编译代码,则返回 true。否则,返回 false。在没有 HiPE 支持的系统中,结果始终为 false