1 记录
1.1 记录和元组
使用记录而不是元组的主要优点是,记录中的字段是通过名称访问的,而元组中的字段是通过位置访问的。为了说明这些差异,假设您想要使用元组 {Name, Address, Phone} 表示一个人。
要编写操作此数据的函数,请记住以下几点
- Name 字段是元组的第一个元素。
- Address 字段是第二个元素。
- Phone 字段是第三个元素。
例如,要从包含此类元组的变量 P 中提取数据,您可以编写以下代码,然后使用模式匹配提取相关字段
Name = element(1, P), Address = element(2, P), ...
此类代码难以阅读和理解,如果元组中元素的编号错误,就会发生错误。如果字段的数据表示形式发生变化,通过重新排序、添加或删除字段,则必须检查所有对人员元组的引用,并可能进行修改。
记录允许通过名称而不是通过位置来引用字段。在以下示例中,使用记录而不是元组来存储数据
-record(person, {name, phone, address}).
这使得可以通过名称引用记录的字段。例如,如果 P 是一个变量,其值为一个 person 记录,以下代码访问记录的名称和地址字段
Name = P#person.name, Address = P#person.address, ...
在内部,记录使用带标签的元组表示
{person, Name, Phone, Address}
1.2 定义记录
以下 person 定义在本节中的几个示例中使用。它包含三个字段: name、 phone 和 address。 name 和 phone 的默认值分别是 "" 和 []。 address 的默认值是原子 undefined,因为此字段没有提供默认值
-record(person, {name = "", phone = [], address}).
必须在 shell 中定义记录,才能在示例中使用记录语法
> rd(person, {name = "", phone = [], address}).
person
这是因为记录定义只在编译时可用,不在运行时可用。有关 shell 中记录的详细信息,请参阅 STDLIB 中的 shell(3) 手册页。
1.3 创建记录
新 person 记录的创建方式如下
> #person{phone=[0,8,2,3,4,3,1,2], name="Robert"}.
#person{name = "Robert",phone = [0,8,2,3,4,3,1,2],address = undefined}
由于 address 字段被省略,因此使用其默认值。
从 Erlang 5.1/OTP R8B 开始,可以使用特殊字段 _ 为记录中的所有字段设置值。 _ 表示“所有未明确指定的字段”。
示例
> #person{name = "Jakob", _ = '_'}.
#person{name = "Jakob",phone = '_',address = '_'}
它主要用于 ets:match/2 和 mnesia:match_object/3,将记录字段设置为原子 '_'。(这是 ets:match/2 中的通配符。)
1.4 访问记录字段
以下示例展示了如何访问记录字段
> P = #person{name = "Joe", phone = [0,8,2,3,4,3,1,2]}. #person{name = "Joe",phone = [0,8,2,3,4,3,1,2],address = undefined} > P#person.name. "Joe"
1.5 更新记录
以下示例展示了如何更新记录
> P1 = #person{name="Joe", phone=[1,2,3], address="A street"}. #person{name = "Joe",phone = [1,2,3],address = "A street"} > P2 = P1#person{name="Robert"}. #person{name = "Robert",phone = [1,2,3],address = "A street"}
1.6 类型测试
以下示例展示了如果 P 是类型为 person 的记录,则保护成功
foo(P) when is_record(P, person) -> a_person; foo(_) -> not_a_person.
1.7 模式匹配
模式匹配可以与记录结合使用,如以下示例所示
> P3 = #person{name="Joe", phone=[0,0,7], address="A street"}. #person{name = "Joe",phone = [0,0,7],address = "A street"} > #person{name = Name} = P3, Name. "Joe"
以下函数接受一个 person 记录列表,并搜索具有特定名称的人的电话号码
find_phone([#person{name=Name, phone=Phone} | _], Name) -> {found, Phone}; find_phone([_| T], Name) -> find_phone(T, Name); find_phone([], Name) -> not_found.
模式中引用的字段可以以任何顺序给出。
1.8 嵌套记录
记录中字段的值可以是记录实例。可以逐步或一步到位地检索嵌套数据,如以下示例所示
-record(name, {first = "Robert", last = "Ericsson"}). -record(person, {name = #name{}, phone}). demo() -> P = #person{name= #name{first="Robert",last="Virding"}, phone=123}, First = (P#person.name)#name.first.
此处, demo() 评估为 "Robert"。
1.9 更长的示例
以下示例中嵌入了注释
%% File: person.hrl %%----------------------------------------------------------- %% Data Type: person %% where: %% name: A string (default is undefined). %% age: An integer (default is undefined). %% phone: A list of integers (default is []). %% dict: A dictionary containing various information %% about the person. %% A {Key, Value} list (default is the empty list). %%------------------------------------------------------------ -record(person, {name, age, phone = [], dict = []}).
-module(person). -include("person.hrl"). -compile(export_all). % For test purposes only. %% This creates an instance of a person. %% Note: The phone number is not supplied so the %% default value [] will be used. make_hacker_without_phone(Name, Age) -> #person{name = Name, age = Age, dict = [{computer_knowledge, excellent}, {drinks, coke}]}. %% This demonstrates matching in arguments print(#person{name = Name, age = Age, phone = Phone, dict = Dict}) -> io:format("Name: ~s, Age: ~w, Phone: ~w ~n" "Dictionary: ~w.~n", [Name, Age, Phone, Dict]). %% Demonstrates type testing, selector, updating. birthday(P) when is_record(P, person) -> P#person{age = P#person.age + 1}. register_two_hackers() -> Hacker1 = make_hacker_without_phone("Joe", 29), OldHacker = birthday(Hacker1), % The central_register_server should have % an interface function for this. central_register_server ! {register_person, Hacker1}, central_register_server ! {register_person, OldHacker#person{name = "Robert", phone = [0,8,3,2,4,5,3,1]}}.