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
必须是一个原子。