檢視原始碼 記錄
記錄與元組
使用記錄而非元組的主要優勢在於,記錄中的欄位是透過名稱存取的,而元組中的欄位則是透過位置存取的。為了說明這些差異,假設您想要用元組 {Name, Address, Phone}
來表示一個人。
為了編寫處理此資料的函式,請記住以下幾點
Name
欄位是元組的第一個元素。Address
欄位是第二個元素。Phone
欄位是第三個元素。
例如,要從包含此元組的變數 P
中提取資料,您可以編寫以下程式碼,然後使用模式匹配來提取相關欄位
Name = element(1, P),
Address = element(2, P),
...
此程式碼難以閱讀和理解,如果元組中元素的編號錯誤,就會發生錯誤。如果欄位的資料表示方式發生變更(透過重新排序、新增或移除欄位),則必須檢查並可能修改所有對 person 元組的參考。
記錄允許透過名稱而非位置來參考欄位。在以下範例中,使用記錄而非元組來儲存資料
-record(person, {name, phone, address}).
這使得可以透過名稱參考記錄的欄位。例如,如果 P
是一個變數,其值為 person
記錄,則以下程式碼會存取記錄的姓名和地址欄位
Name = P#person.name,
Address = P#person.address,
...
在內部,記錄是使用帶標籤的元組表示的
{person, Name, Phone, Address}
定義記錄
本節的幾個範例中使用了以下 person
的定義。包含三個欄位,分別是 name
、phone
和 address
。name
和 phone
的預設值分別是 "" 和 []。address
的預設值是原子 undefined
,因為沒有為此欄位提供預設值
-record(person, {name = "", phone = [], address}).
必須在 Shell 中定義記錄,才能在範例中使用記錄語法
> rd(person, {name = "", phone = [], address}).
person
這是因為記錄定義僅在編譯時可用,而不在執行時可用。有關 Shell 中記錄的詳細資訊,請參閱 STDLIB 中的 shell
手冊頁。
建立記錄
新的 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
中的萬用字元。)
存取記錄欄位
以下範例示範如何存取記錄欄位
> 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"
更新記錄
以下範例示範如何更新記錄
> 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"}
類型測試
以下範例顯示,如果 P
是 person
類型的記錄,則 guard 會成功
foo(P) when is_record(P, person) -> a_person;
foo(_) -> not_a_person.
模式匹配
匹配可以與記錄結合使用,如下列範例所示
> 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.
模式中引用的欄位可以按任何順序給定。
巢狀記錄
記錄中欄位的值可以是記錄的實例。巢狀資料的擷取可以逐步完成,也可以一步完成,如下列範例所示
-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"
。
更長的範例
以下範例中嵌入了註解
%% 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]}}.