11  记录

11 记录

记录是一种用于存储固定数量元素的数据结构。它具有命名字段,类似于 C 中的结构体。记录表达式在编译期间被转换为元组表达式。因此,除非采取特殊措施,否则 shell 无法理解记录表达式。有关详细信息,请参阅 STDLIB 中的 shell(3) 手册页。

更多示例在 编程示例 中提供。

记录定义由记录的名称和记录的字段名称组成。记录和字段名称必须是原子。每个字段都可以指定一个可选的默认值。如果没有提供默认值,则使用 undefined

-record(Name, {Field1 [= Value1],
               ...
               FieldN [= ValueN]}).

记录定义可以放置在模块的属性和函数声明中的任何位置,但定义必须在任何使用记录之前。

如果记录在多个模块中使用,建议将记录定义放在包含文件中。

以下表达式创建一个新的 Name 记录,其中每个字段 FieldI 的值是求值对应表达式 ExprI 的结果。

#Name{Field1=Expr1,...,FieldK=ExprK}

字段可以按任意顺序排列,不一定与记录定义中的顺序相同,并且可以省略字段。省略的字段将获取其各自的默认值。

如果多个字段要分配相同的值,可以使用以下结构

#Name{Field1=Expr1,...,FieldK=ExprK, _=ExprL}

然后,省略的字段将获取求值 ExprL 的结果,而不是其默认值。此特性主要用于创建 ETS 和 Mnesia 匹配函数的模式。

示例

-record(person, {name, phone, address}).

...

lookup(Name, Tab) ->
    ets:match_object(Tab, #person{name=Name, _='_'}).
Expr#Name.Field

返回指定字段的值。 Expr 应该求值为 Name 记录。

以下表达式返回指定字段在记录元组表示中的位置

#Name.Field

示例

-record(person, {name, phone, address}).

...

lookup(Name, List) ->
    lists:keysearch(Name, #person.name, List).
Expr#Name{Field1=Expr1,...,FieldK=ExprK}

Expr 应该求值为 Name 记录。返回此记录的副本,其中每个指定字段 FieldI 的值更改为求值对应表达式 ExprI 的结果。所有其他字段保留其旧值。

由于记录表达式扩展为元组表达式,因此允许在守卫中创建记录和访问记录字段。但是,所有子表达式(例如,用于字段初始化的子表达式)也必须是有效的守卫表达式。

示例

handle(Msg, State) when Msg==#msg{to=void, no=3} ->
    ...

handle(Msg, State) when State#state.running==true ->
    ...

还有一个类型测试 BIF is_record(Term, RecordTag)

示例

is_person(P) when is_record(P, person) ->
    true;
is_person(_P) ->
    false.

与创建记录的方式相同,创建匹配特定记录的模式

#Name{Field1=Expr1,...,FieldK=ExprK}

在这种情况下,Expr1...ExprK 中的一个或多个可以是未绑定的变量。

假设以下记录定义

-record(nrec0, {name = "nested0"}).
-record(nrec1, {name = "nested1", nrec0=#nrec0{}}).
-record(nrec2, {name = "nested2", nrec1=#nrec1{}}).

N2 = #nrec2{},

访问或更新嵌套记录可以不使用括号编写

"nested0" = N2#nrec2.nrec1#nrec1.nrec0#nrec0.name,
    N0n = N2#nrec2.nrec1#nrec1.nrec0#nrec0{name = "nested0a"},

等效于

"nested0" = ((N2#nrec2.nrec1)#nrec1.nrec0)#nrec0.name,
N0n = ((N2#nrec2.nrec1)#nrec1.nrec0)#nrec0{name = "nested0a"},
更改

在 Erlang/OTP R14 之前,访问或更新嵌套记录时需要使用括号。

记录表达式在编译期间被转换为元组表达式。定义为

-record(Name, {Field1,...,FieldN}).

的记录在内部表示为元组

{Name,Value1,...,ValueN}

这里,每个 ValueIFieldI 的默认值。

在编译过程中,将向每个使用记录的模块添加一个伪函数,以获取有关记录的信息

record_info(fields, Record) -> [Field]
record_info(size, Record) -> Size

Size 是元组表示的大小,即字段数量加一。

此外,#Record.Name 返回记录 RecordName 在元组表示中的索引。

Name 必须是原子。