11 记录
记录是一种用于存储固定数量元素的数据结构。它具有命名字段,类似于 C 中的结构体。记录表达式在编译期间被转换为元组表达式。因此,除非采取特殊措施,否则 shell 无法理解记录表达式。有关详细信息,请参阅 STDLIB 中的 shell(3) 手册页。
更多示例在 编程示例 中提供。
11.1 定义记录
记录定义由记录的名称和记录的字段名称组成。记录和字段名称必须是原子。每个字段都可以指定一个可选的默认值。如果没有提供默认值,则使用 undefined。
-record(Name, {Field1 [= Value1], ... FieldN [= ValueN]}).
记录定义可以放置在模块的属性和函数声明中的任何位置,但定义必须在任何使用记录之前。
如果记录在多个模块中使用,建议将记录定义放在包含文件中。
11.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, _='_'}).
11.3 访问记录字段
Expr#Name.Field
返回指定字段的值。 Expr 应该求值为 Name 记录。
以下表达式返回指定字段在记录元组表示中的位置
#Name.Field
示例
-record(person, {name, phone, address}). ... lookup(Name, List) -> lists:keysearch(Name, #person.name, List).
11.4 更新记录
Expr#Name{Field1=Expr1,...,FieldK=ExprK}
Expr 应该求值为 Name 记录。返回此记录的副本,其中每个指定字段 FieldI 的值更改为求值对应表达式 ExprI 的结果。所有其他字段保留其旧值。
11.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.
11.6 模式中的记录
与创建记录的方式相同,创建匹配特定记录的模式
#Name{Field1=Expr1,...,FieldK=ExprK}
在这种情况下,Expr1...ExprK 中的一个或多个可以是未绑定的变量。
11.7 嵌套记录
假设以下记录定义
-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 之前,访问或更新嵌套记录时需要使用括号。
11.8 记录的内部表示
记录表达式在编译期间被转换为元组表达式。定义为
-record(Name, {Field1,...,FieldN}).
的记录在内部表示为元组
{Name,Value1,...,ValueN}
这里,每个 ValueI 是 FieldI 的默认值。
在编译过程中,将向每个使用记录的模块添加一个伪函数,以获取有关记录的信息
record_info(fields, Record) -> [Field] record_info(size, Record) -> Size
Size 是元组表示的大小,即字段数量加一。
此外,#Record.Name 返回记录 Record 的 Name 在元组表示中的索引。
Name 必须是原子。