在线文档教程
Erlang 20

10.记录 | 10. Records

10项记录

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

提供了更多示例Programming Examples

10.1定义记录

记录定义包括记录的名称,后跟记录的字段名称。记录和字段名称必须是原子。每个字段可以被赋予一个可选的默认值。如果没有提供默认值,undefined则使用。

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

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

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

10.2创造记录

以下表达式创建一个新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, _='_'}).

10.3访问记录字段

Expr#Name.Field

返回指定字段的值。Expr是评估一个Name记录。

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

#Name.Field

例子:

-record(person, {name, phone, address}). ... lookup(Name, List) -> lists:keysearch(Name, #person.name, List).

10.4更新记录

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

Expr是评估一个Name记录。将返回此记录的副本,每个指定字段FieldI的值更改为评估相应表达式的值ExprI。所有其他领域保留其旧值。

10.5守卫记录

由于记录表达式扩展为元组表达式,因此在守卫中允许创建记录和访问记录字段。但是,例如,对于字段启动,所有的子表达式也必须是有效的警戒表达式。

例子:

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.

10.6记录模式

与创建记录相同的方式创建匹配某个记录的模式:

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

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

10.7嵌套记录

从Erlang/OTP R14开始,在访问或更新嵌套记录时可以省略括号。假定以下记录定义:

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

在R14之前,需要括号如下:

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

自R14以来,还可以写以下内容:

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

10.8记录的内部表述

在编译期间,记录表达式被翻译成元组表达式。定义为:

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

在内部由元组表示:

{Name,Value1,...,ValueN}

这里每个ValueI都是默认值FieldI

对于每个使用记录的模块,编译期间会添加一个伪函数以获取有关记录的信息:

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

Size 是元组表示的大小,即比字段数多一个。

另外,#Record.Name返回Name记录的元组表示中的索引Record

Name 必须是一个原子。