5  模块

5  模块

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

有关函数声明的描述,请参见 函数声明语法

模块属性定义了模块的特定属性。

模块属性包含一个标签和一个值

-Tag(Value).

Tag 必须是原子,而 Value 必须是文字项。作为对用户定义属性的方便操作,如果文字项 Value 的语法为 Name/Arity(其中 Name 是原子,Arity 是正整数),则项 Name/Arity 将被转换为 {Name,Arity}

可以指定任何模块属性。这些属性存储在编译后的代码中,可以通过调用 Module:module_info(attributes) 或使用 STDLIB 中的模块 beam_lib(3) 来检索。

几个模块属性具有预定义的含义。其中一些属性的元数为二,但用户定义的模块属性的元数必须为一。

预定义模块属性应放在任何函数声明之前。

模块声明,定义模块的名称。名称 Module(一个原子)应与文件名减去扩展名 .erl 相同。否则,代码加载 无法按预期工作。

此属性应首先指定,并且是唯一必填属性。

导出函数。指定模块内定义的哪些函数在模块外部可见。

Functions 是一个列表 [Name1/Arity1, ..., NameN/ArityN],其中每个 NameI 都是一个原子,ArityI 是一个整数。

导入函数。可以像本地函数一样调用,即无需任何模块前缀。

Module(一个原子)指定要从中导入函数的模块。 Functions 是与 export 相似的列表。

编译器选项。 Options 是单个选项或选项列表。在编译模块时,此属性将添加到选项列表中。请参阅编译器中的 compile(3) 手册页。

模块版本。 Vsn 是任何文字项,可以使用 beam_lib:version/1 检索,请参阅 STDLIB 中的 beam_lib(3) 手册页。

如果没有指定此属性,则版本默认为模块的 MD5 校验和。

此属性命名一个函数,该函数将在模块加载时自动运行。有关更多信息,请参见 模块加载时运行函数

指定模块内定义的哪些函数可以作为 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 - 类型和函数规范,该规范不再更新。

虽然它不是模块属性,而是指令(因为它可能影响语法),但存在 -feature(..) 指令,用于启用和禁用 特性

语法与属性类似,但有两个参数

-feature(FeatureName, enable | disable).

请注意,feature 指令 只能出现在模块的前缀中。

注释可以放在模块中的任何位置,但不能放在字符串和引用的原子中。注释以字符 "%" 开头,一直延续到下一行结束处,但不包括下一行结束处,并且没有影响。请注意,终止行结束符的作用是空格。

编译器会自动将两个特殊的导出函数插入到每个模块中

  • Module:module_info/0
  • Module:module_info/1

可以调用这些函数来检索有关模块的信息。

每个模块中的 module_info/0 函数返回一个包含有关模块信息的 {Key,Value} 元组列表。目前,该列表包含带有以下 Key 的元组:moduleattributescompileexportsmd5native。元组的顺序和数量可能会在未经事先通知的情况下更改。

调用 module_info(Key),其中 Key 是一个原子,会返回有关模块的单个信息。

以下值允许用于 Key

返回一个表示模块名称的原子。

返回一个 {AttributeName,ValueList} 元组列表,其中 AttributeName 是属性的名称,而 ValueList 是一个值的列表。请注意,如果属性在模块中出现多次,则该属性可以在列表中出现多次,并具有不同的值。

如果模块使用 beam_lib(3) 模块(在 STDLIB 中)进行剥离,则属性列表将变为空。

返回一个包含有关模块编译方式信息的元组列表。如果模块使用 beam_lib(3) 模块(在 STDLIB 中)进行剥离,则此列表将为空。

返回表示模块 MD5 校验和的二进制数据。

返回一个 {Name,Arity} 元组列表,其中包含模块中所有导出的函数。

返回一个 {Name,Arity} 元组列表,其中包含模块中所有函数。

返回一个 {Name,Arity} 元组列表,其中包含模块中所有 NIF 函数。

如果模块具有原生编译代码,则返回 true。否则,返回 false。在没有 HiPE 支持的系统中,结果始终为 false