Запись
Модуль для работы с записями, определения и импорта записей.
Записи — это просто кортежи, где первый элемент — атом:
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__. Он возвращает список карт с типом записи, именем, тегом и полями. Атрибут доступен только внутри определения модуля.
Охранные условия
- is_record(данные)
-
Проверяет, является ли данная
dataзаписью. - is_record(данные, тип)
-
Проверяет, является ли данная
dataзаписью типаkind.
Функции
- defrecord(имя, тег \\ nil, kv)
-
Определяет набор макросов для создания, доступа и сопоставления с образцом в записи.
- defrecordp(имя, тег \\ nil, kv)
-
То же, что и
defrecord/3, но генерирует приватные макросы. - extract(имя, параметры)
-
Извлекает информацию о записи из файла Erlang.
- extract_all(параметры)
-
Извлекает всю информацию о всех записях из файла Erlang.
is_record(данные)Исходный код
Проверяет, является ли данная data записью.
Это реализовано как макрос, чтобы его можно было использовать в условиях охраны.
Примеры
Record.is_record({User, "john", 27})
#=> true
Record.is_record({})
#=> false
is_record(данные, тип)Исходный код
Проверяет, является ли данная data записью типа kind.
Это реализовано как макрос, чтобы его можно было использовать в условиях охраны.
Примеры
iex> record = {User, "john", 27}
iex> Record.is_record(record, User)
true
defrecord(имя, тег \\ nil, kv)Исходный код
Определяет набор макросов для создания, доступа и сопоставления с образцом в записи.
Имя сгенерированных макросов будет 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
defrecordp(имя, тег \\ nil, kv)Исходный код
То же, что и defrecord/3, но генерирует приватные макросы.
extract(имя, параметры)Исходный код
@spec extract( name :: atom(), keyword() ) :: keyword()
Извлекает информацию о записи из файла Erlang.
Возвращает выражение с цитированием, содержащее поля в виде списка кортежей.
name, которое является именем извлеченной записи, ожидается, что будет атомом *на этапе компиляции*.
Параметры
Эта функция требует одного из следующих параметров, которые являются взаимоисключающими (т.е. только один из них может быть использован в одном вызове):
:from— (бинарное представление пути к файлу) путь к файлу Erlang, содержащему определение записи для извлечения; с этим параметром эта функция использует тот же поиск по пути, который используется атрибутом-includeв модулях Erlang.:from_lib— (бинарное представление пути к файлу) путь к файлу Erlang, содержащему определение записи для извлечения; с этим параметром эта функция использует тот же поиск по пути, который используется атрибутом-include_libв модулях Erlang.
Она также принимает следующие дополнительные необязательные параметры, которые не являются взаимоисключающими:
: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 ]
extract_all(параметры)Исходный код
@spec extract_all(keyword()) :: [{name :: atom(), keyword()}]Извлекает всю информацию о всех записях из файла Erlang.
Возвращает список ключевых слов {record_name, fields} кортежей, где record_name — имя извлеченной записи, а fields — список {field, value} кортежей, представляющих поля для этой записи.
Параметры
Принимает те же параметры, что и для Record.extract/2.
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.15.4/Record.html