查看源码 记录
记录是一种用于存储固定数量元素的数据结构。它具有命名的字段,类似于 C 语言中的结构体。记录表达式在编译期间会被转换为元组表达式。
更多示例请参见编程示例。
定义记录
记录定义由记录的名称和记录的字段名称组成。记录和字段名称必须是原子(atoms)。每个字段都可以给定一个可选的默认值。如果没有提供默认值,则使用 undefined
。
-record(Name, {Field1 [= Expr1],
...
FieldN [= ExprN]}).
字段的默认值可以是任意表达式,但不能使用任何变量。
记录定义可以放在模块的属性和函数声明之间的任何位置,但定义必须在使用记录之前。
如果一个记录在多个模块中使用,建议将记录定义放在一个包含文件中。
更改
从 Erlang/OTP 26 开始,可以使用本节中描述的语法在 Erlang shell 中定义记录。在较早的版本中,必须使用
shell
内置函数rd/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, _='_'}).
访问记录字段
Expr#Name.Field
返回指定字段的值。Expr
的计算结果必须为 Name
记录。
示例:
-record(person, {name, phone, address}).
get_person_name(Person) ->
Person#person.name.
以下表达式返回记录的元组表示中指定字段的位置
#Name.Field
示例
-record(person, {name, phone, address}).
lookup(Name, List) ->
lists:keyfind(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}
这里,每个 ValueI
是 FieldI
的默认值。
在编译期间,会向使用记录的每个模块添加一个伪函数,以获取有关记录的信息
record_info(fields, Record) -> [Field]
record_info(size, Record) -> Size
Size
是元组表示的大小,即比字段数多 1。