檢視原始碼 記錄
記錄是一種用於儲存固定數量元素的資料結構。它具有命名字段,類似於 C 語言中的結構 (struct)。記錄表達式在編譯期間會被轉換為元組表達式。
更多範例請參閱程式設計範例。
定義記錄
記錄定義由記錄名稱以及記錄的欄位名稱組成。記錄和欄位名稱必須是原子 (atom)。每個欄位都可以選擇性地設定預設值。如果未提供預設值,則使用 undefined
。
-record(Name, {Field1 [= Expr1],
...
FieldN [= ExprN]}).
欄位的預設值可以是任意表達式,但不能使用任何變數。
記錄定義可以放置在模組的屬性和函數宣告的任何位置,但定義必須在記錄的任何使用之前。
如果一個記錄在多個模組中使用,建議將記錄定義放在 include 檔案中。
變更
從 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
的值。所有其他欄位都保留它們的舊值。
在 Guard 中使用記錄
由於記錄表達式會擴展為元組表達式,因此允許在 guard 中建立記錄和存取記錄欄位。但是,所有子表達式(用於初始化欄位)也必須是有效的 guard 表達式。
範例
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
是元組表示的大小,也就是欄位數加一。