Запись
Модуль для работы с записями, их определения и импорта.
Записи — это просто кортежи, где первый элемент — атом:
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.14.1/Record.html