檢視原始碼 記錄 (Elixir v1.16.2)
與記錄共用、定義和匯入的模組。
記錄僅為第一個元素為原子的元組
iex> Record.is_record({User, "john", 27})
true
此模組提供在編譯時使用記錄的便利性,其中編譯時欄位名稱用於處理元組,提供元組緊湊結構上的快速運算。
在 Elixir 中,記錄主要用於兩種情況
- 處理簡短的內部資料
- 與 Erlang 記錄介面
巨集 defrecord/3
和 defrecordp/3
可用於建立記錄,而 extract/2
和 extract_all/1
可用於從 Erlang 檔案中萃取記錄。
類型
可以使用 record/2
巨集為元組定義類型(僅在類型規格中可用)。此巨集會擴充為元組,如下面的範例所示
defmodule MyModule do
require Record
Record.defrecord(:user, name: "john", age: 25)
@type user :: record(:user, name: String.t(), age: integer)
# expands to: "@type user :: {:user, String.t(), integer}"
end
反射
如果模組中有任何記錄,可透過讀取 @__records__
模組屬性來擷取所有記錄的清單。它會傳回一個清單,其中包含記錄種類、名稱、標籤和欄位。此屬性僅在模組定義中可用。
摘要
守衛
函數
定義一組巨集,用於建立、存取和模式比對記錄。
所產生巨集的名稱將會是 name
(必須是原子)。tag
也是原子,用作記錄的「標籤」(亦即記錄元組的第一個元素);預設(如果為 nil
)則與 name
相同。kv
是新記錄的 name: default_value
欄位的關鍵字清單。
會產生下列巨集
name/0
用所有欄位的預設值建立新的記錄name/1
用給定的欄位和值建立新的記錄,取得記錄中給定欄位的零為基準索引,或將給定的記錄轉換為關鍵字清單name/2
用給定的欄位和值更新現有的記錄,或存取給定記錄中的給定欄位
所有這些巨集都是公開巨集(由 defmacro
定義)。
有關如何使用這些巨集的範例,請參閱「範例」區段。
範例
defmodule User do
require Record
Record.defrecord(:user, name: "meg", age: "25")
end
在上面的範例中,會定義一組名為 user
但具有不同元數的巨集,用於操作基礎記錄。
# Import the module to make the user macros locally available
import User
# To create records
record = user() #=> {:user, "meg", 25}
record = user(age: 26) #=> {:user, "meg", 26}
# To get a field from the record
user(record, :name) #=> "meg"
# To update the record
user(record, age: 26) #=> {:user, "meg", 26}
# To get the zero-based index of the field in record tuple
# (index 0 is occupied by the record "tag")
user(:name) #=> 1
# Convert a record to a keyword list
user(record) #=> [name: "meg", age: 26]
也可以使用產生的巨集來比對記錄的模式,並在比對期間繫結變數
record = user() #=> {:user, "meg", 25}
user(name: name) = record
name #=> "meg"
預設情況下,Elixir 會使用記錄名稱作為元組的第一個元素(「標籤」)。不過,在定義記錄時可以指定不同的標籤,如下列範例所示,其中我們使用 Customer
作為 defrecord/3
的第二個引數
defmodule User do
require Record
Record.defrecord(:user, Customer, name: nil)
end
require User
User.user() #=> {Customer, nil}
在值中使用匿名函數定義萃取的記錄
如果記錄在預設值中定義匿名函數,就會產生 ArgumentError
。在從使用匿名函數作為預設值的 Erlang 函式庫萃取記錄後定義記錄時,可能會不小心發生這種情況。
Record.defrecord(:my_rec, Record.extract(...))
** (ArgumentError) invalid value for record field fun_field,
cannot escape #Function<12.90072148/2 in :erl_eval.expr/5>.
若要解決這個錯誤,請使用您自己的 &M.f/a 函數重新定義欄位,如下所示
defmodule MyRec do
require Record
Record.defrecord(:my_rec, Record.extract(...) |> Keyword.merge(fun_field: &__MODULE__.foo/2))
def foo(bar, baz), do: IO.inspect({bar, baz})
end
與 defrecord/3
相同,但會產生私有巨集。
從 Erlang 檔案中萃取記錄資訊。
傳回包含欄位(以元組清單表示)的引述表達式。
name
,也就是萃取記錄的名稱,預期在編譯時會是原子。
選項
這個函數需要下列選項之一,這些選項彼此互斥(亦即,在同一個呼叫中只能使用其中一個選項)
:from
- (表示檔案路徑的二進位)包含要萃取的記錄定義的 Erlang 檔案路徑;使用這個選項時,這個函數會使用與 Erlang 模組中使用的-include
屬性相同的路徑查詢。:from_lib
- (表示檔案路徑的二進位)包含要萃取的記錄定義的 Erlang 檔案路徑;使用這個選項時,這個函數會使用與 Erlang 模組中使用的-include_lib
屬性相同的路徑查詢。
它另外接受下列非互斥的選用選項
:includes
- (以二進位表示的目錄清單)如果要萃取的記錄依賴於相對包含,這個選項允許開發人員指定那些相對包含存在的目錄。:macros
- (巨集名稱和值的關鍵字清單)如果要萃取的記錄依賴於巨集的值,這個選項允許設定那些巨集的值。
預期這些選項在編譯時會是文字(包括二進位值)。
範例
iex> Record.extract(:file_info, from_lib: "kernel/include/file.hrl")
[
size: :undefined,
type: :undefined,
access: :undefined,
atime: :undefined,
mtime: :undefined,
ctime: :undefined,
mode: :undefined,
links: :undefined,
major_device: :undefined,
minor_device: :undefined,
inode: :undefined,
uid: :undefined,
gid: :undefined
]
從 Erlang 檔案中萃取所有記錄資訊。
傳回關鍵字清單,其中包含 {record_name, fields}
元組,其中 record_name
是萃取記錄的名稱,而 fields
是 {field, value}
元組清單,代表該記錄的欄位。
選項
接受與 Record.extract/2
列出的相同選項。