Ядро
Kernel — это стандартная среда Elixir.
Она в основном состоит из:
- базовых языковых примитивов, таких как арифметические операторы, создание процессов, обработка типов данных и другие
- макросов для управления потоком и определения новых функций (модули, функции и т. п.)
- условий для дополнения сопоставления с образцом
Вы можете вызывать функции и макросы Kernel в любом месте кода Elixir без использования префикса Kernel., так как они все автоматически импортированы. Например, в IEx, вы можете вызвать:
iex> is_number(13) true
Если вы не хотите импортировать функцию или макрос из Kernel, используйте опцию :except и затем перечислите функцию/макрос по арности:
import Kernel, except: [if: 2, unless: 2]
См. Kernel.SpecialForms.import/2 для получения дополнительной информации об импорте.
В Elixir также есть специальные формы, которые всегда импортируются и не могут быть пропущены. Они описаны в Kernel.SpecialForms.
Стандартная библиотека
Kernel предоставляет базовые возможности, на которых построена стандартная библиотека Elixir. Рекомендуется изучить стандартную библиотеку для получения расширенной функциональности. Вот основные группы модулей в стандартной библиотеке (этот список не является полным справочником, см. боковую панель документации для всех записей).
Встроенные типы
Следующие модули обрабатывают встроенные типы данных Elixir:
-
Atom- литеральные константы с именем (true,false, иnilявляются атомами) -
Float- числа с плавающей точкой -
Function- ссылка на фрагмент кода, созданный с помощью специальной формыfn/1 -
Integer- целые числа (не дроби) -
List- коллекции переменного числа элементов (связные списки) -
Map- коллекции пар ключ-значение -
Process- лёгкие потоки выполнения -
Port- механизмы взаимодействия с внешним миром -
Tuple- коллекции фиксированного числа элементов
Существует два типа данных без сопровождающего модуля:
- Bitstring - последовательность битов, созданная с помощью
Kernel.SpecialForms.<<>>/1. Когда количество битов делится на 8, они называются двоичными и могут быть обработаны с помощью модуля Erlang:binary - Reference - уникальное значение в системе выполнения, созданное с помощью
make_ref/0
Типы данных
Elixir также предоставляет другие типы данных, построенные на основе перечисленных выше типов. Некоторые из них:
-
Date-year-month-dayструктуры в заданном календаре -
DateTime- дата и время с часовым поясом в заданном календаре -
Exception- данные, генерируемые при ошибках и непредвиденных ситуациях -
MapSet- неупорядоченные коллекции уникальных элементов -
NaiveDateTime- дата и время без часового пояса в заданном календаре -
Keyword- списки пар из двух элементов, часто представляющие необязательные значения -
Range- включающие диапазоны между двумя целыми числами -
Regex- регулярные выражения -
String- двоичные данные UTF-8, представляющие символы -
Time-hour:minute:secondструктуры в заданном календаре -
URI- представление URI, идентифицирующих ресурсы -
Version- представление версий и требований
Системные модули
Модули, взаимодействующие с основой системы, такие как:
-
IO- обрабатывает ввод и вывод -
File- взаимодействует с файловой системой -
Path- обрабатывает пути к файлам -
System- считывает и записывает системную информацию
Протоколы
Протоколы добавляют полиморфный диспетчер в Elixir. Они являются контрактами, реализуемыми типами данных. См. defprotocol/2 для получения дополнительной информации о протоколах. Elixir предоставляет следующие протоколы в стандартной библиотеке:
-
Collectable- собирает данные в тип данных -
Enumerable- обрабатывает коллекции в Elixir. МодульEnumпредоставляет жадные функции для работы с коллекциями, модульStreamпредоставляет ленивые функции -
Inspect- преобразует типы данных в их представление в языке программирования -
List.Chars- преобразует типы данных в их представление во внешнем мире как charlist (не на основе программирования) -
String.Chars- преобразует типы данных в их представление во внешнем мире как строки (не на основе программирования)
Функциональность, ориентированная на процессы и приложения
Следующие модули основаны на процессах, чтобы предоставить конкурентность, отказоустойчивость и многое другое.
-
Agent- процесс, который инкапсулирует изменяемое состояние -
Application- функции для запуска, остановки и настройки приложений -
GenServer- универсальный API клиент-сервер -
Registry- хранилище пар ключ-значение на основе процессов -
Supervisor- процесс, который отвечает за запуск, надзор и остановку других процессов -
Task- процесс, который выполняет вычисления -
Task.Supervisor- надзор за процессами, управляющими исключительно задачами
Дополнительные документы
Документация Elixir также включает дополнительные документы в разделе "Страницы". Это:
- Совместимость и устаревшие функции - список совместимости между каждой версией Elixir и Erlang/OTP, схема релизов; список всех устаревших функций, когда они были устаревшими и альтернативы
- Рекомендации по написанию библиотек - общие рекомендации, антипаттерны и правила для тех, кто пишет библиотеки
- Конвенции именования - правила именования кода Elixir
- Операторы - список всех операторов Elixir и их приоритет
- Шаблоны и условия - введение в шаблоны, условия и расширения
- Справочник по синтаксису - справочник по синтаксису языка
- Типы данных- типы и спецификации функций, включая список типов
- Синтаксис Unicode - описание поддержки Unicode в Elixir
- Написание документации - рекомендации по написанию документации в Elixir
Условия
Этот модуль включает встроенные условия, используемые разработчиками Elixir. Это предопределённый набор функций и макросов, которые дополняют сопоставление с образцом, обычно вызываемые после оператора when. Например:
def drive(%User{age: age}) when age >= 16 do
...
end
Данный блок кода будет выполнен только если возраст пользователя равен или больше 16. Условия также поддерживают объединение нескольких условий с помощью and и or. Весь блок условий истиннен, если все выражения условия будут оценены как true. Более полное введение в условия доступно на странице "Шаблоны и условия".
Встраивание
Некоторые функции, описанные в этом модуле, встраиваются компилятором Elixir в свои эквиваленты Erlang в модуле :erlang. Эти функции в Erlang называются BIF (встроенные внутренние функции) и обладают интересными свойствами, так как некоторые из них разрешены в условиях, а другие используются для оптимизации компилятора.
Большинство встроенных функций можно увидеть при записи функции:
iex> &Kernel.is_atom/1 &:erlang.is_atom/1
Эти функции будут явно отмечены в их документации как «встроенные компилятором».
Истинностные и ложные значения
Помимо булевых значений true и false, в Elixir есть понятие «истинностного» или «ложного» значения.
- значение истинно, когда оно не является
falseи не являетсяnil - значение ложно, когда оно является либо
false, либоnil
Elixir имеет функции, такие как and/2, которые работают только с булевыми значениями, но также функции, которые работают с этими истинностными/ложными значениями, такие как &&/2 и !/1.
Примеры
Мы можем проверить истинность значения, используя функцию !/1 дважды.
Истинностные значения:
iex> !!true true iex> !!5 true iex> !![1,2] true iex> !!"foo" true
Ложные значения (их ровно два):
iex> !!false false iex> !!nil false
Резюме
Условия
- left != right
Возвращает
trueесли два выражения не равны.- left !== right
Возвращает
trueесли два выражения не точно равны.- left * right
Арифметическое умножение.
- +value
Арифметическое унарное сложение.
- left + right
Арифметическое сложение.
- -value
Арифметическое унарное вычитание.
- left - right
Арифметическое вычитание.
- left / right
Арифметическое деление.
- left < right
Возвращает
trueесли left меньше right.- left <= right
Возвращает
trueесли left меньше или равно right.- left == right
Возвращает
trueесли два выражения равны.- left === right
Возвращает
trueесли два выражения точно равны.- left > right
Возвращает
trueесли left больше right.- left >= right
Возвращает
trueесли left больше или равно right.- abs(number)
Возвращает целое число или число с плавающей запятой, которое является абсолютным значением
number.- left and right
Логическое И.
- binary_part(binary, start, length)
Извлекает часть бинарного представления, начиная с
startдлинойlength. Бинарные представления индексируются с нуля.- bit_size(bitstring)
Возвращает целое число, которое представляет размер в битах
bitstring.- byte_size(bitstring)
Возвращает количество байтов, необходимых для хранения
bitstring.- ceil(number)
Возвращает наименьшее целое число, большее или равное
number.- div(dividend, divisor)
Выполняет целочисленное деление.
- elem(tuple, index)
Получает элемент по нулевому
indexиндексу вtuple.- floor(number)
Возвращает наибольшее целое число, меньшее или равное
number.- hd(list)
Возвращает голову списка. Вызывает
ArgumentError, если список пустой.- left in right
Проверяет, является ли элемент слева членом коллекции справа.
- is_atom(term)
Возвращает
trueеслиtermявляется атомом; в противном случае возвращаетfalse.- is_binary(term)
Возвращает
trueеслиtermявляется бинарным; в противном случае возвращаетfalse.- is_bitstring(term)
Возвращает
trueеслиtermявляется битовой строкой (включая бинарное представление); в противном случае возвращаетfalse.- is_boolean(term)
Возвращает
trueеслиtermявляется либо атомомtrue, либо атомомfalse(т.е. булевым значением); в противном случае возвращаетfalse.- is_float(term)
Возвращает
trueеслиtermявляется числом с плавающей точкой; в противном случае возвращаетfalse.- is_function(term)
Возвращает
trueеслиtermявляется функцией; в противном случае возвращаетfalse.- is_function(term, arity)
Возвращает
trueеслиtermявляется функцией, которая может применяться сarityаргументами; в противном случае возвращаетfalse.- is_integer(term)
Возвращает
trueеслиtermявляется целым числом; в противном случае возвращаетfalse.- is_list(term)
Возвращает
trueеслиtermявляется списком с нулем или более элементами; в противном случае возвращаетfalse.- is_map(term)
Возвращает
trueеслиtermявляется словарем; в противном случае возвращаетfalse.- is_map_key(map, key)
Возвращает
trueеслиkeyявляется ключом вmap; в противном случае возвращаетfalse.- is_nil(term)
Возвращает
trueеслиtermявляетсяnil,falseв противном случае.- is_number(term)
Возвращает
trueеслиtermявляется целым числом или числом с плавающей запятой; в противном случае возвращаетfalse.- is_pid(term)
Возвращает
trueеслиtermявляется идентификатором процесса (PID); в противном случае возвращаетfalse.- is_port(term)
Возвращает
trueеслиtermявляется идентификатором порта; в противном случае возвращаетfalse.- is_reference(term)
Возвращает
trueеслиtermявляется ссылкой; в противном случае возвращаетfalse.- is_struct(term)
Возвращает true, если
termявляется структурой; в противном случае возвращаетfalse.- is_tuple(term)
Возвращает
trueеслиtermявляется кортежем; в противном случае возвращаетfalse.- length(list)
Возвращает длину
list.- map_size(map)
Возвращает размер словаря.
- node()
Возвращает атом, представляющий имя локального узла. Если узел не активен, возвращается
:nonode@nohostвместо него.- node(arg)
Возвращает узел, где расположен заданный аргумент. Аргумент может быть PID, ссылкой или портом. Если локальный узел не активен, возвращается
:nonode@nohost.- not(value)
Логическое НЕ.
- left or right
Логическое ИЛИ.
- rem(dividend, divisor)
Вычисляет остаток от целочисленного деления.
- round(number)
Округляет число до ближайшего целого.
- self()
Возвращает PID (идентификатор процесса) вызывающего процесса.
- tl(list)
Возвращает хвост списка. Вызывает
ArgumentError, если список пустой.- trunc(number)
Возвращает целую часть
number.- tuple_size(tuple)
Возвращает размер кортежа.
Функции
- !value
Логическое отрицание.
- left && right
Предлагает оператор короткого замыкания, который вычисляет и возвращает второе выражение только в том случае, если первое выражение вычисляет истинное значение (ни
falseниnil). В противном случае возвращает первое выражение.- left ++ right
Конкатенирует правильный список и термин, возвращая список.
- left -- right
Удаляет первое вхождение элемента в левом списке для каждого элемента в правом.
- first..last
Возвращает диапазон с указанными
firstиlastцелыми числами.- left <> right
Конкатенирует два бинарных значения.
- left =~ right
Сопоставляет термин в
leftс регулярным выражением или строкой вright.- @expr
Читает и записывает атрибуты текущего модуля.
- left |> right
Оператор конвейера.
- left || right
Оператор короткого замыкания, который вычисляет и возвращает второе выражение только в том случае, если первое выражение не вычисляет истинное значение (т. е., оно является либо
nil, либоfalse). В противном случае возвращает первое выражение.- alias!(alias)
При использовании внутри цитирования отмечает, что данный псевдоним не должен быть санпропущен. Это означает, что псевдоним будет расширен при расширении макроса.
- apply(fun, args)
Вызывает заданную анонимную функцию
funсо списком аргументовargs.- apply(module, function_name, args)
Вызывает заданную функцию из
moduleсо списком аргументовargs.- binding(context \\ nil)
Возвращает привязку для данного контекста в виде списка ключевых слов.
- def(call, expr \\ nil)
Определяет публичную функцию с заданным именем и телом.
- defdelegate(funs, opts)
Определяет функцию, которая делегирует другому модулю.
- defexception(fields)
Определяет исключение.
- defguard(guard)
Генерирует макрос, подходящий для использования в выражениях-защитах.
- defguardp(guard)
Генерирует частный макрос, подходящий для использования в выражениях-защитах.
- defimpl(name, opts, do_block \\ [])
Определяет реализацию для данного протокола.
- defmacro(call, expr \\ nil)
Определяет публичный макрос с заданным именем и телом.
- defmacrop(call, expr \\ nil)
Определяет закрытый макрос с заданным именем и телом.
- defmodule(alias, do_block)
Определяет модуль по имени с заданным содержимым.
- defoverridable(keywords_or_behaviour)
Делает указанные функции в текущем модуле переопределяемыми.
- defp(call, expr \\ nil)
Определяет закрытую функцию с заданным именем и телом.
- defprotocol(name, do_block)
Определяет протокол.
- defstruct(fields)
Определяет структуру.
- destructure(left, right)
Разбирает два списка, присваивая каждый термин в правом списке соответствующему термину в левом списке.
- exit(reason)
Останавливает выполнение вызывающего процесса с указанным основанием.
- function_exported?(module, function, arity)
Возвращает
true, еслиmoduleзагружен и содержит публичнуюfunctionс заданнымarity, в противном случаеfalse.- get_and_update_in(path, fun)
Получает значение и обновляет вложенную структуру данных с помощью заданной
path.- get_and_update_in(data, keys, fun)
Получает значение и обновляет вложенную структуру.
- get_in(data, keys)
Получает значение из вложенной структуры.
- if(condition, clauses)
Обеспечивает макрос
if/2.- inspect(term, opts \\ [])
Просматривает заданный аргумент в соответствии с протоколом
Inspect. Второй аргумент — список ключевых слов с параметрами для управления просмотром.- macro_exported?(module, macro, arity)
Возвращает
true, еслиmoduleзагружен и содержит публичныйmacroс заданнымarity, в противном случаеfalse.- make_ref()
Возвращает почти уникальную ссылку.
- match?(pattern, expr)
Макрос-удобство, проверяющий, соответствует ли правая часть (выражение) левой части (шаблону).
- max(first, second)
Возвращает наибольшее из двух заданных терминов в соответствии с порядком терминов Erlang.
- min(first, second)
Возвращает наименьшее из двух заданных терминов в соответствии с порядком терминов Erlang.
- pop_in(path)
Вынимает ключ из вложенной структуры по заданному
path.- pop_in(data, keys)
Вынимает ключ из заданной вложенной структуры.
- put_elem(tuple, index, value)
Задает
valueв заданной нулевойindexвtuple.- put_in(path, value)
Задает значение в вложенной структуре по заданному
path.- put_in(data, keys, value)
Задает значение в вложенную структуру.
- raise(message)
Вызывает исключение.
- raise(exception, attributes)
Вызывает исключение.
- reraise(message, stacktrace)
Вызывает исключение, сохраняя предыдущий стек вызовов.
- reraise(exception, attributes, stacktrace)
Вызывает исключение, сохраняя предыдущий стек вызовов.
- send(dest, message)
Отправляет сообщение заданному
destи возвращает сообщение.
- sigil_C(term, modifiers)
Обрабатывает сигил
~Cдля списков символов.- sigil_D(date_string, modifiers)
Обрабатывает сигил
~Dдля дат.- sigil_N(naive_datetime_string, modifiers)
Обрабатывает сигил
~Nдля неявных дат и времени.- sigil_R(term, modifiers)
Обрабатывает сигил
~Rдля регулярных выражений.- sigil_S(term, modifiers)
Обрабатывает сигил
~Sдля строк.- sigil_T(time_string, modifiers)
Обрабатывает сигил
~Tдля времени.- sigil_U(datetime_string, modifiers)
Обрабатывает сигил
~Uдля создания UTCDateTime.- sigil_W(term, modifiers)
Обрабатывает сигил
~Wдля списков слов.- sigil_c(term, modifiers)
Обрабатывает сигил
~cдля списков символов.- sigil_r(term, modifiers)
Обрабатывает сигил
~rдля регулярных выражений.- sigil_s(term, modifiers)
Обрабатывает сигил
~sдля строк.- sigil_w(term, modifiers)
Обрабатывает сигил
~wдля списков слов.- spawn(fun)
Запускает заданную функцию и возвращает её PID.
- spawn(module, fun, args)
Запускает заданную функцию
funиз заданногоmodule, передавая ей заданныеargs, и возвращает её PID.- spawn_link(fun)
Запускает заданную функцию, связывает её с текущим процессом и возвращает её PID.
- spawn_link(module, fun, args)
Запускает заданную функцию
funиз заданногоmoduleпередавая ей заданныеargs, связывает её с текущим процессом и возвращает её PID.- spawn_monitor(fun)
Запускает заданную функцию, отслеживает её и возвращает её PID и ссылку на отслеживание.
- spawn_monitor(module, fun, args)
Запускает заданный модуль и функцию, передавая аргументы, отслеживает её и возвращает её PID и ссылку на отслеживание.
- struct(struct, fields \\ [])
Создаёт и обновляет структуру.
- struct!(struct, fields \\ [])
Аналогично
struct/2, но проверяет корректность ключей.- throw(term)
Нелокальное возвращение из функции.
- to_charlist(term)
Преобразует заданный терм в список символов в соответствии с протоколом
List.Chars.- to_string(term)
Преобразует аргумент в строку в соответствии с протоколом
String.Chars.- unless(condition, clauses)
Обеспечивает макрос
unless.- update_in(path, fun)
Обновляет вложенную структуру с помощью заданной
path.- update_in(data, keys, fun)
Обновляет ключ вложенной структуры.
- use(module, opts \\ [])
Использует данный модуль в текущем контексте.
- var!(var, context \\ nil)
При использовании внутри цитирования отмечает, что заданная переменная не должна быть гигиенизирована.
Защиты
left != right
Характеристики
term() != term() :: boolean()
Возвращает true если два значения не равны.
Этот оператор считает 1 и 1.0 равными. Для сравнения соответствия используйте !==/2 вместо него.
Все значения в Elixir могут сравниваться друг с другом.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> 1 != 2 true iex> 1 != 1.0 false
left !== right
Характеристики
term() !== term() :: boolean()
Возвращает true если два значения не точно равны.
Все значения в Elixir могут сравниваться друг с другом.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> 1 !== 2 true iex> 1 !== 1.0 true
left * right
Характеристики
integer() * integer() :: integer()
float() * float() :: float()
integer() * float() :: float()
float() * integer() :: float()
Арифметическое умножение.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> 1 * 2 2
+value
Характеристики
+integer() :: integer()
+float() :: float()
Арифметический унарный плюс.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> +1 1
left + right
Характеристики
integer() + integer() :: integer()
float() + float() :: float()
integer() + float() :: float()
float() + integer() :: float()
Арифметическое сложение.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> 1 + 2 3
-value
Характеристики
-0 :: 0
-pos_integer() :: neg_integer()
-neg_integer() :: pos_integer()
-float() :: float()
Арифметический унарный минус.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> -2 -2
left - right
Характеристики
integer() - integer() :: integer()
float() - float() :: float()
integer() - float() :: float()
float() - integer() :: float()
Арифметическое вычитание.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> 1 - 2 -1
left / right
Характеристики
number() / number() :: float()
Арифметическое деление.
Результат всегда является числом с плавающей точкой. Используйте div/2 и rem/2 для целочисленного деления или остатка.
Возбуждает исключение ArithmeticError, если right равно 0 или 0.0.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
1 / 2 #=> 0.5 -3.0 / 2.0 #=> -1.5 5 / 1 #=> 5.0 7 / 0 ** (ArithmeticError) bad argument in arithmetic expression
left < right
Характеристики
term() < term() :: boolean()
Возвращает true если left меньше right.
Все значения в Elixir могут сравниваться друг с другом.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> 1 < 2 true
left <= right
Характеристики
term() <= term() :: boolean()
Возвращает true если left меньше или равно right.
Все значения в Elixir могут сравниваться друг с другом.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> 1 <= 2 true
left == right
Характеристики
term() == term() :: boolean()
Возвращает true если два значения равны.
Этот оператор считает 1 и 1.0 равными. Для более строгого сравнения используйте ===/2 вместо него.
Все значения в Elixir могут сравниваться друг с другом.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> 1 == 2 false iex> 1 == 1.0 true
left === right
Характеристики
term() === term() :: boolean()
Возвращает true если два значения точно равны.
Значения считаются точно равными только если они имеют одинаковое значение и тип. Например, 1 == 1.0 возвращает true, но так как они имеют разные типы, 1 === 1.0 возвращает false.
Все значения в Elixir могут сравниваться друг с другом.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> 1 === 2 false iex> 1 === 1.0 false
left > right
Характеристики
term() > term() :: boolean()
Возвращает true если left больше right.
Все значения в Elixir могут сравниваться друг с другом.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> 1 > 2 false
left >= right
Характеристики
term() >= term() :: boolean()
Возвращает true если left больше или равно right.
Все значения в Elixir могут сравниваться друг с другом.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> 1 >= 2 false
abs(number)
Характеристики
abs(number()) :: number()
Возвращает целое или число с плавающей точкой, являющееся абсолютным значением number.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> abs(-3.33) 3.33 iex> abs(-3) 3
left and right
Логическое И.
Если left равно false, возвращает false; в противном случае возвращает right.
Требует, чтобы только операнд left был булевым, так как он выполняется по короткой цепочке. Если операнд left не является булевым, возбуждается исключение ArgumentError.
Разрешено в проверках условий.
Примеры
iex> true and false false iex> true and "yay!" "yay!"
binary_part(binary, start, length)
Характеристики
binary_part(binary(), non_neg_integer(), integer()) :: binary()
Извлекает часть бинарного объекта, начиная с позиции start длиной length. Бинарные объекты нумеруются с нуля.
Если start или length каким-либо образом выходят за пределы бинарного объекта, возбуждается исключение ArgumentError.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> binary_part("foo", 1, 2)
"oo"
Отрицательное length может использоваться для извлечения байтов, которые предшествуют байту в позиции start:
iex> binary_part("Hello", 5, -3)
"llo" bit_size(bitstring)
Характеристики
bit_size(bitstring()) :: non_neg_integer()
Возвращает целое число, являющееся размером в битах bitstring.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> bit_size(<<433::16, 3::3>>) 19 iex> bit_size(<<1, 2, 3>>) 24
byte_size(bitstring)
Характеристики
byte_size(bitstring()) :: non_neg_integer()
Возвращает количество байтов, необходимых для хранения bitstring.
То есть, если количество бит в bitstring не делится на 8, результирующее количество байтов будет округлено вверх (в большую сторону). Эта операция выполняется за постоянное время.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> byte_size(<<433::16, 3::3>>) 3 iex> byte_size(<<1, 2, 3>>) 3
ceil(number)
Характеристики
ceil(number()) :: integer()
Возвращает наименьшее целое число, большее или равное number.
Если вам нужно выполнить операцию ceil для других знаков после запятой, используйте Float.ceil/2 вместо этого.
Разрешено в проверках условий. Встраивается компилятором.
div(dividend, divisor)
Характеристики
div(integer(), neg_integer() | pos_integer()) :: integer()
Выполняет целочисленное деление.
Возбуждает исключение ArithmeticError, если один из аргументов не является целым числом или когда divisor является 0.
div/2 выполняет обрезанное целочисленное деление. Это означает, что результат всегда округляется к нулю.
Если вам нужно выполнить целочисленное деление с округлением к меньшему целому (к отрицательной бесконечности), используйте Integer.floor_div/2 вместо этого.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
div(5, 2) #=> 2 div(6, -4) #=> -1 div(-99, 2) #=> -49 div(100, 0) ** (ArithmeticError) bad argument in arithmetic expression
elem(tuple, index)
Specs
elem(tuple(), non_neg_integer()) :: term()
Возвращает элемент по нулевой индексации index в tuple.
Вызывает ArgumentError, если индекс отрицательный или выходит за пределы диапазона элементов кортежа.
Разрешено в тестах стражей. Встраивается компилятором.
Примеры
tuple = {:foo, :bar, 3}
elem(tuple, 1)
#=> :bar
elem({}, 0)
** (ArgumentError) argument error
elem({:foo, :bar}, 2)
** (ArgumentError) argument error floor(number)
Specs
floor(number()) :: integer()
Возвращает наибольшее целое число, меньшее или равное number.
Если нужно выполнить операцию округления к меньшему для других десятичных знаков, используйте Float.floor/2.
Разрешено в тестах стражей. Встраивается компилятором.
hd(list)
Specs
hd(nonempty_maybe_improper_list(elem, any())) :: elem when elem: term()
Возвращает голову списка. Вызывает ArgumentError, если список пуст.
Работает со списками неправильной структуры.
Разрешено в тестах стражей. Встраивается компилятором.
Примеры
hd([1, 2, 3, 4]) #=> 1 hd([]) ** (ArgumentError) argument error hd([1 | 2]) #=> 1
left in right
Проверяет, является ли элемент слева членом коллекции справа.
Примеры
iex> x = 1 iex> x in [1, 2, 3] true
Этот оператор (который является макросом) просто переводится в вызов Enum.member?/2. Приведённый выше пример переведётся в:
Enum.member?([1, 2, 3], x)
Elixir также поддерживает left not in right, что эквивалентно not(left in right):
iex> x = 1 iex> x not in [1, 2, 3] false
Стражи
Оператор in/2 (а также not in) может использоваться в условиях стражей, если правая часть представляет собой диапазон или список. В таких случаях Elixir расширит оператор до корректного выражения стража. Например:
when x in [1, 2, 3]
переводится в:
when x === 1 or x === 2 or x === 3
При использовании диапазонов:
when x in 1..3
переводится в:
when is_integer(x) and x >= 1 and x <= 3
Обратите внимание, что только целые числа могут рассматриваться внутри диапазона оператором in.
Учёт AST
left not in right парсится компилятором в AST:
{:not, _, [{:in, _, [left, right]}]}
Это тот же AST, что и not(left in right).
Кроме того, Macro.to_string/2 переведёт все вхождения этого AST в left not in right.
is_atom(term)
Specs
is_atom(term()) :: boolean()
Возвращает true, если term является атомом; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_binary(term)
Specs
is_binary(term()) :: boolean()
Возвращает true, если term является бинарным; в противном случае возвращает false.
Бинарное представление всегда содержит полное количество байтов.
Разрешено в тестах стражей. Встраивается компилятором.
Примеры
iex> is_binary("foo")
true
iex> is_binary(<<1::3>>)
false is_bitstring(term)
Specs
is_bitstring(term()) :: boolean()
Возвращает true, если term является бистроингом (включая бинарное представление); в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
Примеры
iex> is_bitstring("foo")
true
iex> is_bitstring(<<1::3>>)
true is_boolean(term)
Specs
is_boolean(term()) :: boolean()
Возвращает true, если term является либо атомом true, либо атомом false (т.е. булевым значением); в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_float(term)
Specs
is_float(term()) :: boolean()
Возвращает true, если term является числом с плавающей точкой; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_function(term)
Specs
is_function(term()) :: boolean()
Возвращает true, если term является функцией; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_function(term, arity)
Specs
is_function(term(), non_neg_integer()) :: boolean()
Возвращает true, если term является функцией, которая может применяться с arity количеством аргументов; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
Примеры
iex> is_function(fn x -> x * 2 end, 1) true iex> is_function(fn x -> x * 2 end, 2) false
is_integer(term)
Specs
is_integer(term()) :: boolean()
Возвращает true, если term является целым числом; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_list(term)
Specs
is_list(term()) :: boolean()
Возвращает true, если term является списком с нулём или более элементами; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_map(term)
Specs
is_map(term()) :: boolean()
Возвращает true, если term является картой; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_map_key(map, key)
Specs
is_map_key(map(), term()) :: boolean()
Возвращает true, если key является ключом в map; в противном случае возвращает false.
Вызывает BadMapError, если первый элемент не является картой.
Разрешено в тестах стражей. Встраивается компилятором.
is_nil(term)
Возвращает true, если term равно nil; в противном случае возвращает false.
Разрешено в условиях стражей.
Примеры
iex> is_nil(1) false iex> is_nil(nil) true
is_number(term)
Specs
is_number(term()) :: boolean()
Возвращает true, если term является либо целым числом, либо числом с плавающей точкой; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_pid(term)
Specs
is_pid(term()) :: boolean()
Возвращает true, если term является PID (идентификатором процесса); в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_port(term)
Specs
is_port(term()) :: boolean()
Возвращает true, если term является идентификатором порта; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_reference(term)
Specs
is_reference(term()) :: boolean()
Возвращает true, если term является ссылкой; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_struct(term)
Возвращает true, если term является структурой; в противном случае возвращает false.
Разрешено в тестах стражей.
Примеры
iex> is_struct(URI.parse("/"))
true
iex> is_struct(%{})
false is_tuple(term)
Specs
is_tuple(term()) :: boolean()
Возвращает true, если term является кортежем; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
length(list)
Specs
length(list()) :: non_neg_integer()
Возвращает длину list.
Разрешено в тестах стражей. Встраивается компилятором.
Примеры
iex> length([1, 2, 3, 4, 5, 6, 7, 8, 9]) 9
map_size(map)
Характеристики
map_size(map()) :: non_neg_integer()
Возвращает размер карты.
Размер карты — это количество пар ключ-значение, которые содержит карта.
Эта операция выполняется за постоянное время.
Допускается в тестах с защитой. Встраивается компилятором.
Примеры
iex> map_size(%{a: "foo", b: "bar"})
2 node()
Характеристики
node() :: node()
Возвращает атом, представляющий имя локального узла. Если узел не активен, возвращается :nonode@nohost.
Допускается в тестах с защитой. Встраивается компилятором.
node(arg)
Характеристики
node(pid() | reference() | port()) :: node()
Возвращает узел, где находится заданный аргумент. Аргумент может быть PID, ссылкой или портом. Если локальный узел не активен, возвращается :nonode@nohost.
Допускается в тестах с защитой. Встраивается компилятором.
not(value)
Характеристики
not true :: false
not false :: true
Логическое отрицание.
arg должен быть булевым значением; если нет, то генерируется исключение ArgumentError.
Допускается в тестах с защитой. Встраивается компилятором.
Примеры
iex> not false true
left or right
Логическое ИЛИ.
Если left является true, возвращает true; в противном случае возвращает right.
Требуется, чтобы только left операнд был булевым, так как он выполняется по короткой схеме. Если left операнд не является булевым, генерируется исключение ArgumentError.
Допускается в тестах с защитой.
Примеры
iex> true or false true iex> false or 42 42
rem(dividend, divisor)
Характеристики
rem(integer(), neg_integer() | pos_integer()) :: integer()
Вычисляет остаток от деления целых чисел.
Функция rem/2 использует усеченное деление, что означает, что результат всегда будет иметь знак dividend.
Генерирует исключение ArithmeticError, если один из аргументов не является целым числом или когда divisor равно 0.
Допускается в тестах с защитой. Встраивается компилятором.
Примеры
iex> rem(5, 2) 1 iex> rem(6, -4) 2
round(number)
Характеристики
round(number()) :: integer()
Округляет число до ближайшего целого.
Если число равноудалено от двух ближайших целых чисел, то округляется в сторону от нуля.
Допускается в тестах с защитой. Встраивается компилятором.
Примеры
iex> round(5.6) 6 iex> round(5.2) 5 iex> round(-9.9) -10 iex> round(-9) -9 iex> round(2.5) 3 iex> round(-2.5) -3
self()
Характеристики
self() :: pid()
Возвращает PID (идентификатор процесса) вызывающего процесса.
Допускается в защитных условиях. Встраивается компилятором.
tl(list)
Характеристики
tl(nonempty_maybe_improper_list(elem, tail)) :: maybe_improper_list(elem, tail) | tail when elem: term(), tail: term()
Возвращает хвост списка. Генерирует исключение ArgumentError, если список пуст.
Работает со списками нестандартной структуры.
Допускается в тестах с защитой. Встраивается компилятором.
Примеры
tl([1, 2, 3, :go])
#=> [2, 3, :go]
tl([])
** (ArgumentError) argument error
tl([:one])
#=> []
tl([:a, :b | :c])
#=> [:b | :c]
tl([:a | %{b: 1}])
#=> %{b: 1} trunc(number)
Характеристики
trunc(number()) :: integer()
Возвращает целую часть number.
Допускается в тестах с защитой. Встраивается компилятором.
Примеры
iex> trunc(5.4) 5 iex> trunc(-5.99) -5 iex> trunc(-5) -5
tuple_size(tuple)
Характеристики
tuple_size(tuple()) :: non_neg_integer()
Возвращает размер кортежа.
Эта операция выполняется за постоянное время.
Допускается в тестах с защитой. Встраивается компилятором.
Примеры
iex> tuple_size({:a, :b, :c})
3 Функции
!value
Логическое отрицание.
Принимает любой аргумент (не только булевы значения) и возвращает true, если аргумент равен false или nil; в противном случае возвращает false.
Запрещено в защитных условиях.
Примеры
iex> !Enum.empty?([]) false iex> !List.first([]) true
left && right
Представляет оператор короткого замыкания, который вычисляет и возвращает второе выражение только в том случае, если первое выражение имеет истинное значение (не false и не nil). В противном случае возвращает первое выражение.
Запрещено в защитных условиях.
Примеры
iex> Enum.empty?([]) && Enum.empty?([]) true iex> List.first([]) && true nil iex> Enum.empty?([]) && List.first([1]) 1 iex> false && throw(:bad) false
Обратите внимание, что, в отличие от and/2, этот оператор принимает любое выражение в качестве первого аргумента, а не только булевы значения.
left ++ right
Спецификации
list() ++ term() :: maybe_improper_list()
Конкатенирует правильный список и терм, возвращая список.
Сложность a ++ b пропорциональна length(a), поэтому следует избегать многократного добавления в списки произвольной длины, например, list ++ [element]. Вместо этого рассмотрите добавление в начало с помощью [element | rest] и последующего обратного порядка.
Если операнд right не является правильным списком, он возвращает неполный список. Если операнд left не является правильным списком, он вызывает ArgumentError.
Встраивается компилятором.
Примеры
iex> [1] ++ [2, 3] [1, 2, 3] iex> 'foo' ++ 'bar' 'foobar' # returns an improper list iex> [1] ++ 2 [1 | 2] # returns a proper list iex> [1] ++ [2] [1, 2] # improper list on the right will return an improper list iex> [1] ++ [2 | 3] [1, 2 | 3]
left -- right
Спецификации
list() -- list() :: list()
Удаляет первое вхождение элемента в левом списке для каждого элемента в правом списке.
Сложность a -- b пропорциональна length(a) * length(b), что означает, что она будет очень медленной, если и a, и b являются длинными списками. В таких случаях рассмотрите преобразование каждого списка в MapSet и использование MapSet.difference/2.
Встраивается компилятором.
Примеры
iex> [1, 2, 3] -- [1, 2] [3] iex> [1, 2, 3, 2, 1] -- [1, 2, 2] [3, 1]
first..last
Возвращает диапазон с заданными целыми числами first и last.
Если last больше first, диапазон будет увеличиваться от first до last. Если first больше last, диапазон будет уменьшаться от first до last. Если first равно last, диапазон будет содержать один элемент, который является самим числом.
Примеры
iex> 0 in 1..3 false iex> 1 in 1..3 true iex> 2 in 1..3 true iex> 3 in 1..3 true
left <> right
Конкатенирует два бинарных значения.
Примеры
iex> "foo" <> "bar" "foobar"
Оператор <>/2 также может использоваться в сопоставлении с образцом (и в защитных условиях), если левый аргумент является литеральным бинарным значением:
iex> "foo" <> x = "foobar" iex> x "bar"
x <> "bar" = "foobar" привело бы к исключению CompileError.
left =~ right
Спецификации
String.t() =~ (String.t() | Regex.t()) :: boolean()
Сопоставляет терм в left с регулярным выражением или строкой в right.
Возвращает true, если left соответствует right (если это регулярное выражение) или содержит right (если это строка).
Примеры
iex> "abcd" =~ ~r/c(d)/ true iex> "abcd" =~ ~r/e/ false iex> "abcd" =~ "bc" true iex> "abcd" =~ "ad" false iex> "abcd" =~ "" true
@expr
Читает и записывает атрибуты текущего модуля.
Канонический пример атрибутов — это аннотирование того, что модуль реализует поведение OTP, такое как GenServer:
defmodule MyServer do @behaviour GenServer # ... callbacks ... end
По умолчанию Elixir поддерживает все атрибуты модулей, поддерживаемые Erlang, но также можно использовать и пользовательские атрибуты:
defmodule MyServer do @my_data 13 IO.inspect(@my_data) #=> 13 end
В отличие от Erlang, такие атрибуты по умолчанию не сохраняются в модуле, так как в Elixir часто используются пользовательские атрибуты для хранения временных данных, которые будут доступны во время компиляции. Пользовательские атрибуты можно настроить на поведение, более близкое к Erlang, используя Module.register_attribute/3.
Наконец, обратите внимание, что атрибуты также могут быть прочитаны внутри функций:
defmodule MyServer do @my_data 11 def first_data, do: @my_data @my_data 13 def second_data, do: @my_data end MyServer.first_data() #=> 11 MyServer.second_data() #=> 13
Важно отметить, что чтение атрибута создает моментальное изображение его текущего значения. Другими словами, значение считывается во время компиляции, а не во время выполнения. Обратитесь к модулю Module для получения других функций управления атрибутами модуля.
left |> right
Оператор конвейера.
Этот оператор представляет выражение слева в качестве первого аргумента вызова функции справа.
Примеры
iex> [1, [2], 3] |> List.flatten() [1, 2, 3]
Приведённый выше пример эквивалентен вызову List.flatten([1, [2], 3]).
Оператор |> в основном полезен, когда требуется выполнить серию операций, похожих на конвейер:
iex> [1, [2], 3] |> List.flatten() |> Enum.map(fn x -> x * 2 end) [2, 4, 6]
В примере список [1, [2], 3] передаётся в качестве первого аргумента функции List.flatten/1, затем сглаженный список передаётся в качестве первого аргумента функции Enum.map/2, которая удваивает каждый элемент списка.
Другими словами, выражение выше просто преобразуется в:
Enum.map(List.flatten([1, [2], 3]), fn x -> x * 2 end)
Возможные ошибки
При использовании оператора конвейера встречаются две распространённые ошибки.
Первая связана с приоритетом операторов. Например, следующее выражение:
String.graphemes "Hello" |> Enum.reverse
Преобразуется в:
String.graphemes("Hello" |> Enum.reverse())
что приводит к ошибке, так как протокол Enumerable не определён для бинарных данных. Добавление явных скобок устраняет неоднозначность:
String.graphemes("Hello") |> Enum.reverse()
Или, ещё лучше:
"Hello" |> String.graphemes() |> Enum.reverse()
Вторая ошибка заключается в том, что оператор |> работает с вызовами. Например, когда вы пишете:
"Hello" |> some_function()
Elixir видит, что правая часть — это вызов функции, и направляет вызов к ней. Это означает, что если вы хотите направить вызов к анонимной или захваченной функции, она также должна быть явно вызвана.
Учитывая анонимную функцию:
fun = fn x -> IO.puts(x) end
fun.("Hello")
Это не сработает, так как оно вместо этого попытается вызвать локальную функцию fun:
"Hello" |> fun()
Это сработает:
"Hello" |> fun.()
Как видно, оператор |> сохраняет те же семантические свойства, что и при отсутствии оператора конвейера, поскольку оба требуют обозначения fun.(...).
left || right
Оператор короткого замыкания, который вычисляет и возвращает второе выражение только в том случае, если первое выражение не имеет истинного значения (то есть оно либо nil , либо false). В противном случае возвращает первое выражение.
Запрещено в защитных условиях.
Примеры
iex> Enum.empty?([1]) || Enum.empty?([1]) false iex> List.first([]) || true true iex> Enum.empty?([1]) || 1 1 iex> Enum.empty?([]) || throw(:bad) true
Обратите внимание, что, в отличие от or/2, этот оператор принимает любое выражение в качестве первого аргумента, а не только булевы значения.
alias!(alias)
При использовании внутри цитирования отмечает, что заданный псевдоним не должен подвергаться санизации. Это означает, что псевдоним будет расширен при расширении макроса.
См. Kernel.SpecialForms.quote/2 для получения дополнительной информации.
apply(fun, args)
Спецификации
apply((... -> any()), [any()]) :: any()
Вызывает заданную анонимную функцию fun со списком аргументов args.
Встраивается компилятором.
Примеры
iex> apply(fn x -> x * 2 end, [2]) 4
apply(module, function_name, args)
Спецификации
apply(module(), function_name :: atom(), [any()]) :: any()
Вызывает заданную функцию из module со списком аргументов args.
apply/3 используется для вызова функций, где модуль, имя функции или аргументы определяются динамически во время выполнения. По этой причине вы не можете вызывать макросы с помощью apply/3, только функции.
Встраивается компилятором.
Примеры
iex> apply(Enum, :reverse, [[1, 2, 3]]) [3, 2, 1]
binding(context \\ nil)
Возвращает привязку для заданного контекста в виде списка ключевых слов.
В возвращаемом результате ключи — имена переменных, а значения — соответствующие значения переменных.
Если заданный context равен nil (по умолчанию), возвращается привязка для текущего контекста.
Примеры
iex> x = 1 iex> binding() [x: 1] iex> x = 2 iex> binding() [x: 2] iex> binding(:foo) [] iex> var!(x, :foo) = 1 1 iex> binding(:foo) [x: 1]
def(call, expr \\ nil)
Определяет публичную функцию с заданным именем и телом.
Примеры
defmodule Foo do def bar, do: :baz end Foo.bar() #=> :baz
Функцию, ожидающую аргументы, можно определить следующим образом:
defmodule Foo do
def sum(a, b) do
a + b
end
end
В приведенном примере определена sum/2 функция; эта функция получает два аргумента и возвращает их сумму.
Аргументы по умолчанию
\\ используется для задания значения по умолчанию для параметра функции. Например:
defmodule MyMath do
def multiply_by(number, factor \\ 2) do
number * factor
end
end
MyMath.multiply_by(4, 3)
#=> 12
MyMath.multiply_by(4)
#=> 8
Компилятор преобразует это в несколько функций с разной арностью, здесь MyMath.multiply_by/1 и MyMath.multiply_by/2, которые представляют случаи, когда аргументы для параметров со значениями по умолчанию передаются или не передаются.
При определении функции с аргументами по умолчанию и несколькими явно объявленными разделами, необходимо написать заголовок функции, в котором объявляются значения по умолчанию. Например:
defmodule MyString do
def join(string1, string2 \\ nil, separator \\ " ")
def join(string1, nil, _separator) do
string1
end
def join(string1, string2, separator) do
string1 <> separator <> string2
end
end
Обратите внимание, что \\ нельзя использовать с анонимными функциями, так как они могут иметь только одну арность.
Имена функций и переменных
Имена функций и переменных имеют следующий синтаксис: строчная буква ASCII или символ подчеркивания, за которым следуют любые количество строчных или заглавных букв ASCII, цифр или символов подчеркивания. Необязательно, они могут заканчиваться восклицательным знаком или знаком вопроса.
Для переменных любой идентификатор, начинающийся с символа подчеркивания, должен указывать на неиспользуемую переменную. Например:
def foo(bar) do [] end #=> warning: variable bar is unused def foo(_bar) do [] end #=> no warning def foo(_bar) do _bar end #=> warning: the underscored variable "_bar" is used after being set
rescue/catch/after/else
Тела функций поддерживают rescue, catch, after, и else как Kernel.SpecialForms.try/1 делает. Например, следующие две функции эквивалентны:
def format(value) do
try do
format!(value)
catch
:exit, reason -> {:error, reason}
end
end
def format(value) do
format!(value)
catch
:exit, reason -> {:error, reason}
end defdelegate(funs, opts)
Определяет функцию, которая делегирует вызов другому модулю.
Функции, определенные с помощью defdelegate/2, являются публичными и могут вызываться извне модуля, в котором они определены, как если бы они были определены с помощью def/2. Следовательно, defdelegate/2 относится к расширению публичного API текущего модуля. Если вы хотите вызвать функцию, определенную в другом модуле, без использования его полного имени модуля, используйте alias/2 для сокращения имени модуля или import/2 для возможности вызова функции без имени модуля.
Делегирование работает только с функциями; делегирование макросов не поддерживается.
См. def/2 для правил именования и аргументов по умолчанию.
Параметры
:to- модуль, которому будет делегирован вызов.:as- функция, которая будет вызвана в целевом модуле, указанном в:to. Этот параметр является необязательным и по умолчанию равен имени делегируемой функции (funs).
Примеры
defmodule MyList do defdelegate reverse(list), to: Enum defdelegate other_reverse(list), to: Enum, as: :reverse end MyList.reverse([1, 2, 3]) #=> [3, 2, 1] MyList.other_reverse([1, 2, 3]) #=> [3, 2, 1]
defexception(fields)
Определяет исключение.
Исключения представляют собой структуры, поддерживаемые модулем, который реализует поведение Exception. Поведение Exception требует реализации двух функций:
exception/1- получает аргументы, переданные вraise/2, и возвращает структуру исключения. По умолчанию реализация принимает либо набор ключевых аргументов, которые объединяются в структуру, либо строку, которая используется в качестве сообщения об исключении.message/1- получает структуру исключения и должна вернуть его сообщение. Чаще всего исключения имеют поле message, к которому по умолчанию обращается эта функция. Однако, если исключение не имеет поля message, эта функция должна быть явно реализована.
Поскольку исключения являются структурами, API, поддерживаемый defstruct/1, также доступен в defexception/1.
Вызов исключений
Наиболее распространенный способ вызвать исключение — с помощью raise/2:
defmodule MyAppError do
defexception [:message]
end
value = [:hello]
raise MyAppError,
message: "did not get what was expected, got: #{inspect(value)}"
Во многих случаях удобнее передавать ожидаемое значение в raise/2 и генерировать сообщение в обратном вызове Exception.exception/1:
defmodule MyAppError do
defexception [:message]
@impl true
def exception(value) do
msg = "did not get what was expected, got: #{inspect(value)}"
%MyAppError{message: msg}
end
end
raise MyAppError, value
В приведенном примере показана предпочтительная стратегия для настройки сообщений об исключениях.
defguard(guard)
Спецификации
defguard(Macro.t()) :: Macro.t()
Генерирует макрос, подходящий для использования в выражениях стражей.
Возникает во время компиляции, если определение использует выражения, которые не разрешены в стражах, а в противном случае создает макрос, который может использоваться как внутри, так и вне стражей.
Обратите внимание, что по соглашению в Elixir функции/макросы, разрешенные в стражах, имеют префикс is_, такой как is_list/1. Однако, если функция/макрос возвращает булево значение и не разрешена в стражах, она не должна иметь префикс и заканчиваться знаком вопроса, такой как Keyword.keyword?/1.
Пример
defmodule Integer.Guards do
defguard is_even(value) when is_integer(value) and rem(value, 2) == 0
end
defmodule Collatz do
@moduledoc "Tools for working with the Collatz sequence."
import Integer.Guards
@doc "Determines the number of steps `n` takes to reach `1`."
# If this function never converges, please let me know what `n` you used.
def converge(n) when n > 0, do: step(n, 0)
defp step(1, step_count) do
step_count
end
defp step(n, step_count) when is_even(n) do
step(div(n, 2), step_count + 1)
end
defp step(n, step_count) do
step(3 * n + 1, step_count + 1)
end
end defguardp(guard)
Спецификации
defguardp(Macro.t()) :: Macro.t()
Генерирует приватный макрос, подходящий для использования в выражениях стражей.
Возникает во время компиляции, если определение использует выражения, которые не разрешены в стражах, а в противном случае создает приватный макрос, который может использоваться как внутри, так и вне стражей в текущем модуле.
Подобно defmacrop/2, defguardp/1 должен быть определен перед его использованием в текущем модуле.
defimpl(name, opts, do_block \\ [])
Определяет реализацию для данного протокола.
См. модуль Protocol для получения дополнительной информации.
defmacro(call, expr \\ nil)
Определяет публичный макрос с заданным именем и телом.
Макросы должны быть определены перед их использованием.
См. def/2 для правил именования и аргументов по умолчанию.
Примеры
defmodule MyLogic do
defmacro unless(expr, opts) do
quote do
if !unquote(expr), unquote(opts)
end
end
end
require MyLogic
MyLogic.unless false do
IO.puts("It works")
end defmacrop(call, expr \\ nil)
Определяет приватный макрос с заданным именем и телом.
Приватные макросы доступны только из того же модуля, в котором они определены.
Приватные макросы должны быть определены перед их использованием.
См. defmacro/2 для получения дополнительной информации и def/2 для правил именования и аргументов по умолчанию.
defmodule(alias, do_block)
Определяет модуль с заданным именем и содержимым.
Этот макрос определяет модуль с заданным alias в качестве имени и заданным содержимым. Он возвращает кортеж из четырех элементов:
:module- имя модуля
- бинарное содержимое модуля
- результат вычисления блока содержимого
Примеры
defmodule Number do
def one, do: 1
def two, do: 2
end
#=> {:module, Number, <<70, 79, 82, ...>>, {:two, 0}}
Number.one()
#=> 1
Number.two()
#=> 2
Вложенность
Вложенность модуля внутри другого модуля влияет на имя вложенного модуля:
defmodule Foo do defmodule Bar do end end
В приведенном примере создаются два модуля — Foo и Foo.Bar. При вложенности Elixir автоматически создает псевдоним для внутреннего модуля, что позволяет получить доступ ко второму модулю Foo.Bar как к Bar в той же лексической области, где он определен (модуль Foo). Это происходит только в том случае, если вложенный модуль определен с помощью псевдонима.
Если модуль Foo.Bar перемещен в другое место, ссылки на Bar в модуле Foo необходимо обновить до полностью квалифицированного имени (Foo.Bar) или псевдоним нужно явно задать в модуле Foo с помощью Kernel.SpecialForms.alias/2.
defmodule Foo.Bar do # code end defmodule Foo do alias Foo.Bar # code here can refer to "Foo.Bar" as just "Bar" end
Динамические имена
Имена модулей Elixir могут быть динамически сгенерированы. Это очень полезно при работе с макросами. Например, можно написать:
defmodule String.to_atom("Foo#{1}") do
# contents ...
end
Elixir примет любое имя модуля, при условии, что выражение, переданное в качестве первого аргумента defmodule/2, вычисляется в атом. Обратите внимание, что когда используется динамическое имя, Elixir не будет вкладывать имя в текущий модуль и не будет автоматически устанавливать псевдоним.
Зарезервированные имена модулей
Если вы попытаетесь определить модуль, который уже существует, появится предупреждение о том, что модуль был переопределен.
Существуют некоторые модули, которые Elixir в настоящее время не реализует, но может реализовать в будущем. Эти модули зарезервированы, и их определение приведет к ошибке компиляции:
defmodule Any do # code end ** (CompileError) iex:1: module Any is reserved and cannot be defined
Elixir зарезервировал следующие имена модулей: Elixir, Any, BitString, PID, и Reference.
defoverridable(keywords_or_behaviour)
Делает заданные функции в текущем модуле переопределяемыми.
Переопределяемая функция определяется лениво, позволяя разработчику переопределить её.
Макросы не могут быть переопределены как функции, и наоборот.
Пример
defmodule DefaultMod do
defmacro __using__(_opts) do
quote do
def test(x, y) do
x + y
end
defoverridable test: 2
end
end
end
defmodule InheritMod do
use DefaultMod
def test(x, y) do
x * y + super(x, y)
end
end
Как видно в примере выше, super может быть использован для вызова реализации по умолчанию.
Если @behaviour определено, defoverridable также может быть вызвано с модулем в качестве аргумента. Все реализованные обратные вызовы из поведения выше вызова defoverridable будут помечены как переопределяемые.
Пример
defmodule Behaviour do
@callback foo :: any
end
defmodule DefaultMod do
defmacro __using__(_opts) do
quote do
@behaviour Behaviour
def foo do
"Override me"
end
defoverridable Behaviour
end
end
end
defmodule InheritMod do
use DefaultMod
def foo do
"Overridden"
end
end defp(call, expr \\ nil)
Определяет частную функцию с заданным именем и телом.
Частные функции доступны только из модуля, в котором они определены. Попытка получить доступ к частной функции извне модуля, в котором она определена, приводит к исключению UndefinedFunctionError.
См. def/2 для получения дополнительной информации.
Примеры
defmodule Foo do
def bar do
sum(1, 2)
end
defp sum(a, b), do: a + b
end
Foo.bar()
#=> 3
Foo.sum(1, 2)
** (UndefinedFunctionError) undefined function Foo.sum/2 defprotocol(name, do_block)
Определяет протокол.
См. модуль Protocol для получения дополнительной информации.
defstruct(fields)
Определяет структуру.
Структура — это помеченная карта, которая позволяет разработчикам предоставлять значения по умолчанию для ключей, теги для использования в полиморфных диспетчеризациях и утверждениях на этапе компиляции.
Для определения структуры разработчик должен определить обе функции __struct__/0 и __struct__/1. defstruct/1 — это макрос удобства, который определяет такие функции с некоторыми удобствами.
Для получения дополнительной информации о структурах, пожалуйста, см. Kernel.SpecialForms.%/2.
Примеры
defmodule User do defstruct name: nil, age: nil end
Поля структуры оцениваются на этапе компиляции, что позволяет им быть динамическими. В примере ниже, 10 + 11 вычисляется на этапе компиляции, и поле age хранится со значением 21.
defmodule User do defstruct name: nil, age: 10 + 11 end
Аргумент fields обычно представляет собой список ключевых слов с именами полей в качестве атомных ключей и значениями по умолчанию в качестве соответствующих значений. defstruct/1 также поддерживает список атомов в качестве аргумента: в этом случае атомы в списке будут использоваться как имена полей структуры, и по умолчанию они будут иметь значение nil.
defmodule Post do defstruct [:title, :content, :author] end
Наследование
Хотя структуры являются картами, по умолчанию структуры не реализуют ни одного из протоколов, реализованных для карт. Например, попытка использовать протокол со структурой User приводит к ошибке:
john = %User{name: "John"}
MyProtocol.call(john)
** (Protocol.UndefinedError) protocol MyProtocol not implemented for %User{...}
defstruct/1, однако, позволяет реализовывать протоколы путем наследования. Это можно сделать путем определения атрибута @derive в виде списка перед вызовом defstruct/1:
defmodule User do @derive [MyProtocol] defstruct name: nil, age: 10 + 11 end MyProtocol.call(john) # it works!
Для каждого протокола в списке @derive Elixir будет проверять, реализован ли протокол для Any. Если реализация протокола Any определяет обратный вызов __deriving__/3, обратный вызов будет вызван, и он должен определить реализующий модуль. В противном случае реализация, которая просто указывает на реализацию Any , автоматически наследована. Для получения дополнительной информации об обратном вызове __deriving__/3 см. Protocol.derive/3.
Принуждение к ключам
При создании структуры Elixir автоматически гарантирует, что все ключи принадлежат структуре:
%User{name: "john", unknown: :key}
** (KeyError) key :unknown not found in: %User{age: 21, name: nil}
Elixir также позволяет разработчикам принудительно устанавливать определенные ключи, которые всегда должны быть указаны при создании структуры:
defmodule User do @enforce_keys [:name] defstruct name: nil, age: 10 + 11 end
Теперь попытка создать структуру без ключа name завершится ошибкой:
%User{age: 21}
** (ArgumentError) the following keys must also be given when building struct User: [:name]
Обратите внимание, что @enforce_keys является простым гарантией на этапе компиляции, помогающей разработчикам при создании структур. Он не применяется к обновлениям и не обеспечивает никакой проверки значений.
Типы
Рекомендуется определять типы для структур. По соглашению такой тип называется t. Для определения структуры внутри типа используется синтаксис литерала структуры:
defmodule User do
defstruct name: "John", age: 25
@type t :: %__MODULE__{name: String.t(), age: non_neg_integer}
end
Рекомендуется использовать синтаксис структуры только при определении типа структуры. При ссылке на другую структуру лучше использовать User.t вместо %User{}.
Типы полей структуры, которые не включены в %User{} , по умолчанию являются term() (см. term/0).
Структуры, внутренняя структура которых является частной для локального модуля (сопоставление с образцом или прямой доступ к полям которых не должен быть разрешен), должны использовать атрибут @opaque. Структуры, чья внутренняя структура является публичной, должны использовать атрибут @type.
destructure(left, right)
Распаковывает два списка, присваивая каждый элемент в правом списке соответствующему элементу в левом списке.
В отличие от сопоставления с образцом через =, если размеры левого и правого списков не совпадают, распаковка просто останавливается вместо выдачи ошибки.
Примеры
iex> destructure([x, y, z], [1, 2, 3, 4, 5])
iex> {x, y, z}
{1, 2, 3}
В примере выше, даже если у правого списка больше элементов, чем у левого, распаковка работает нормально. Если правый список меньше, оставшиеся элементы просто устанавливаются в значение nil:
iex> destructure([x, y, z], [1])
iex> {x, y, z}
{1, nil, nil}
Левая часть поддерживает любые выражения, которые вы бы использовали в левой части сопоставления:
x = 1 destructure([^x, y, z], [1, 2, 3])
Приведенный выше пример будет работать только в том случае, если x совпадает с первым значением в правом списке. В противном случае, он выдаст ошибку MatchError (как это делает оператор =).
exit(reason)
Спецификации
exit(term()) :: no_return()
Останавливает выполнение вызывающего процесса с указанной причиной.
Поскольку вычисление этой функции приводит к завершению процесса, она не возвращает значения.
Встраивается компилятором.
Примеры
Когда процесс достигает конца, по умолчанию он завершается с причиной :normal. Вы также можете явно вызвать exit/1, если хотите завершить процесс, но не сигнализировать об ошибке:
exit(:normal)
В случае возникновения проблем, вы также можете использовать exit/1 с другой причиной:
exit(:seems_bad)
Если причина выхода не :normal, все процессы, связанные с завершившимся процессом, аварийно завершатся (если они не обрабатывают выходы).
Выходы OTP
Выходы используются OTP для определения, завершился ли процесс аномально или нет. Следующие выходы считаются «нормальными»:
exit(:normal)exit(:shutdown)exit({:shutdown, term})
Завершение с любой другой причиной считается аномальным и рассматривается как сбой. Это означает, что включается поведение по умолчанию для надзирателя, генерируются отчеты об ошибках и т. д.
На это поведение полагаются во многих местах. Например, ExUnit использует exit(:shutdown) при завершении процесса теста для сигнализации связанным процессам, деревьям наблюдения и т. д., чтобы вежливо завершить работу тоже.
Выходы CLI
Исходя из сигналов выхода, упомянутых выше, если процесс, запущенный из командной строки, завершается с любой из трёх вышеуказанных причин, его выход считается нормальным, и процесс операционной системы завершается со статусом 0.
Однако возможно настроить сигнал выхода операционной системы вызовом:
exit({:shutdown, integer})
Это заставит процесс операционной системы завершиться со статусом, заданным integer , одновременно сигнализируя всем связанным процессам Erlang вежливо завершить свою работу.
Любая другая причина выхода приведет к завершению процесса операционной системы со статусом 1 и аварийному завершению связанных процессов Erlang.
function_exported?(module, function, arity)
Спецификации
function_exported?(module(), atom(), arity()) :: boolean()
Возвращает true, если module загружен и содержит публичную function с заданным arity, в противном случае false.
Обратите внимание, что эта функция не загружает модуль, если он не загружен. См. Code.ensure_loaded/1 для получения дополнительной информации.
Встраивается компилятором.
Примеры
iex> function_exported?(Enum, :map, 2) true iex> function_exported?(Enum, :map, 10) false iex> function_exported?(List, :to_string, 1) true
get_and_update_in(path, fun)
Получает значение и обновляет вложенную структуру данных с помощью заданной path.
Это аналогично get_and_update_in/3, за исключением того, что путь извлекается с помощью макроса, а не передается в виде списка. Например:
get_and_update_in(opts[:foo][:bar], &{&1, &1 + 1})
Эквивалентно:
get_and_update_in(opts, [:foo, :bar], &{&1, &1 + 1})
Это также работает со вложенными структурами и способом задания путей struct.path.to.value.
get_and_update_in(struct.foo.bar, &{&1, &1 + 1})
Обратите внимание, что для работы этого макроса весь путь должен быть всегда виден этим макросом. См. раздел "Пути" ниже.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users["john"].age, &{&1, &1 + 1})
{27, %{"john" => %{age: 28}, "meg" => %{age: 23}}}
Пути
Путь может начинаться с переменной, локального или удалённого вызова и должен быть последован одним или несколькими:
foo[bar]- обращается к ключуbarвfoo; в случае, еслиfooравно nil, возвращаетсяnilfoo.bar- обращается к полю карты/структуры; в случае отсутствия поля генерируется ошибка
Вот некоторые допустимые пути:
users["john"][:age] users["john"].age User.all()["john"].age all_users()["john"].age
Вот некоторые недопустимые:
# Does a remote call after the initial value users["john"].do_something(arg1, arg2) # Does not access any key or field users
get_and_update_in(data, keys, fun)
Характеристики
get_and_update_in(
structure :: Access.t(),
keys,
(term() -> {get_value, update_value} | :pop)
) :: {get_value, structure :: Access.t()}
when keys: [any(), ...], update_value: term(), get_value: var Получает значение и обновляет вложенную структуру.
data — это вложенная структура (то есть карта, список ключевых слов или структура, которая реализует поведение Access).
Аргумент fun получает значение key (или nil, если key отсутствует) и должен вернуть одно из следующих значений:
кортеж из двух элементов
{get_value, new_value}. В этом случаеget_value— это извлечённое значение, которое может быть обработано перед возвратом.new_value— это новое значение, которое должно быть сохранено подkey.:pop, что подразумевает удаление текущего значения подkeyиз структуры и возврат этого значения.
Эта функция использует модуль Access для перемещения по структурам в соответствии с заданными keys, если key не является функцией, что подробно описано в последующем разделе.
Примеры
Эта функция полезна, когда необходимо получить текущее значение (или что-то, вычисленное на основе текущего значения) и обновить его одновременно. Например, она может использоваться для чтения текущего возраста пользователя и увеличения его на единицу за один проход:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users, ["john", :age], &{&1, &1 + 1})
{27, %{"john" => %{age: 28}, "meg" => %{age: 23}}}
Функции в качестве ключей
Если ключ является функцией, функция будет вызвана с тремя аргументами:
- операция (
:get_and_update) - данные для доступа
- функция, которая будет вызвана далее
Это означает, что get_and_update_in/3 можно расширить для предоставления пользовательских поисков. Недостатком является то, что функции не могут храниться в качестве ключей в доступных структурах данных.
Когда один из ключей является функцией, функция вызывается. В примере ниже мы используем функцию для получения и инкрементирования всех возрастов в списке:
iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> all = fn :get_and_update, data, next ->
...> data |> Enum.map(next) |> Enum.unzip()
...> end
iex> get_and_update_in(users, [all, :age], &{&1, &1 + 1})
{[27, 23], [%{name: "john", age: 28}, %{name: "meg", age: 24}]}
Если предыдущее значение до вызова функции — nil, функция получит nil в качестве значения и должна обработать его соответствующим образом (либо путем отказа, либо путем предоставления разумного значения по умолчанию).
Модуль Access поставляется со многими удобными функциями доступа, такими как анонимная функция all , определённая выше. Смотрите Access.all/0, Access.key/2 и другие в качестве примеров.
get_in(data, keys)
Характеристики
get_in(Access.t(), [term(), ...]) :: term()
Получает значение из вложенной структуры.
Использует модуль Access для перемещения по структурам в соответствии с заданными keys, если key не является функцией, что подробно описано в последующем разделе.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users, ["john", :age])
27
В случае, если любой из ключей возвращает nil, будет возвращено nil:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users, ["unknown", :age])
nil
Функции в качестве ключей
Если ключ является функцией, функция будет вызвана с тремя аргументами:
- операция (
:get) - данные для доступа
- функция, которая будет вызвана далее
Это означает, что get_in/2 можно расширить для предоставления пользовательских поисков. В примере ниже мы используем функцию для получения всех карт в списке:
iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> all = fn :get, data, next -> Enum.map(data, next) end
iex> get_in(users, [all, :age])
[27, 23]
Если предыдущее значение до вызова функции — nil, функция получит nil в качестве значения и должна обработать его соответствующим образом.
Модуль Access поставляется со многими удобными функциями доступа, такими как анонимная функция all , определённая выше. Смотрите Access.all/0, Access.key/2 и другие в качестве примеров.
if(condition, clauses)
Предоставляет макрос if/2.
Этот макрос ожидает, что первый аргумент будет условием, а второй — списком ключевых слов.
Примеры с одной строкой
if(foo, do: bar)
В примере выше, bar будет возвращено, если foo вычисляется как истинное значение (не false и не nil). В противном случае будет возвращено nil.
Можно указать опцию else, чтобы указать обратное:
if(foo, do: bar, else: baz)
Примеры с блоками
Также можно передать блок в макрос if/2. Первый пример выше был бы преобразован в:
if foo do bar end
Обратите внимание, что do/end становятся разделителями. Второй пример был бы преобразован в:
if foo do bar else baz end
Для сравнения более чем двух предложений необходимо использовать макрос cond/1.
inspect(term, opts \\ [])
Характеристики
inspect(Inspect.t(), keyword()) :: String.t()
Проверяет заданный аргумент в соответствии с протоколом Inspect. Второй аргумент — это список ключевых слов с параметрами для управления проверкой.
Параметры
inspect/2 принимает список параметров, которые внутренне преобразуются в структуру Inspect.Opts. Проверьте документацию по Inspect.Opts, чтобы узнать о поддерживаемых параметрах.
Примеры
iex> inspect(:foo)
":foo"
iex> inspect([1, 2, 3, 4, 5], limit: 3)
"[1, 2, 3, ...]"
iex> inspect([1, 2, 3], pretty: true, width: 0)
"[1,\n 2,\n 3]"
iex> inspect("olá" <> <<0>>)
"<<111, 108, 195, 161, 0>>"
iex> inspect("olá" <> <<0>>, binaries: :as_strings)
"\"olá\\0\""
iex> inspect("olá", binaries: :as_binaries)
"<<111, 108, 195, 161>>"
iex> inspect('bar')
"'bar'"
iex> inspect([0 | 'bar'])
"[0, 98, 97, 114]"
iex> inspect(100, base: :octal)
"0o144"
iex> inspect(100, base: :hex)
"0x64"
Обратите внимание, что протокол Inspect не обязательно возвращает допустимое представление термина Elixir. В таких случаях возвращаемое значение проверки должно начинаться с #. Например, проверка функции вернёт:
inspect(fn a, b -> a + b end) #=> #Function<...>
Протокол Inspect может быть изменён, чтобы скрыть определённые поля из структур, поэтому они не отображаются в логах, результатах проверки и т. п. См. раздел «Наследование» в документации по протоколу Inspect для получения дополнительной информации.
macro_exported?(module, macro, arity)
Характеристики
macro_exported?(module(), atom(), arity()) :: boolean()
Возвращает true если module загружено и содержит публичный macro с заданным arity, иначе false.
Обратите внимание, что эта функция не загружает модуль, если он не загружен. Смотрите Code.ensure_loaded/1 для получения дополнительной информации.
Если module — это модуль Erlang (в отличие от модуля Elixir), эта функция всегда возвращает false.
Примеры
iex> macro_exported?(Kernel, :use, 2) true iex> macro_exported?(:erlang, :abs, 1) false
make_ref()
Характеристики
make_ref() :: reference()
Возвращает почти уникальную ссылку.
Возвращаемая ссылка появится снова примерно после 2^82 вызовов; поэтому она достаточно уникальна для практических целей.
Встроено в компилятор.
Примеры
make_ref() #=> #Reference<0.0.0.135>
match?(pattern, expr)
Удобный макрос, который проверяет, соответствует ли правая часть (выражение) левой части (шаблону).
Примеры
iex> match?(1, 1)
true
iex> match?({1, _}, {1, 2})
true
iex> map = %{a: 1, b: 2}
iex> match?(%{a: _}, map)
true
iex> a = 1
iex> match?(^a, 1)
true
match?/2 очень полезен при фильтрации или поиске значения в перечислимом объекте:
iex> list = [a: 1, b: 2, a: 3]
iex> Enum.filter(list, &match?({:a, _}, &1))
[a: 1, a: 3]
Также можно задавать условия соответствия:
iex> list = [a: 1, b: 2, a: 3]
iex> Enum.filter(list, &match?({:a, x} when x < 2, &1))
[a: 1]
Однако, переменные, присвоенные в соответствии, недоступны за пределами вызова функции (в отличие от обычного соответствия шаблонов с оператором =):
iex> match?(_x, 1) true iex> binding() []
max(first, second)
Характеристики
max(first, second) :: first | second when first: term(), second: term()
Возвращает наибольшее из двух заданных терминов в соответствии с порядком терминов Erlang.
Если термины сравниваются как равные, возвращается первый.
Встроено компилятором.
Примеры
iex> max(1, 2) 2 iex> max(:a, :b) :b
Использование порядка терминов Erlang означает, что сравнения структурные, а не семантические. Например, при сравнении дат:
iex> max(~D[2017-03-31], ~D[2017-04-01]) ~D[2017-03-31]
В приведенном выше примере max/2 вернул 31 марта, а не 1 апреля, потому что структурное сравнение сравнивает день до года. В таких случаях модули обычно предоставляют функции, такие как Date.compare/2, которые выполняют семантическое сравнение.
min(first, second)
Характеристики
min(first, second) :: first | second when first: term(), second: term()
Возвращает наименьшее из двух заданных терминов в соответствии с порядком терминов Erlang.
Если термины сравниваются как равные, возвращается первый.
Встроено компилятором.
Примеры
iex> min(1, 2)
1
iex> min("foo", "bar")
"bar"
Использование порядка терминов Erlang означает, что сравнения структурные, а не семантические. Например, при сравнении дат:
iex> min(~D[2017-03-31], ~D[2017-04-01]) ~D[2017-04-01]
В приведенном выше примере min/2 вернул 1 апреля, а не 31 марта, потому что структурное сравнение сравнивает день до года. В таких случаях модули обычно предоставляют функции, такие как Date.compare/2, которые выполняют семантическое сравнение.
pop_in(path)
Удаляет ключ из вложенной структуры по заданному path.
Это похоже на pop_in/2, за исключением того, что путь извлекается с помощью макроса, а не путем передачи списка. Например:
pop_in(opts[:foo][:bar])
Эквивалентно:
pop_in(opts, [:foo, :bar])
Обратите внимание, что для работы этого макроса весь путь должен всегда быть виден этому макросу. Дополнительную информацию о поддерживаемых выражениях путей см. в документации get_and_update_in/2.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> pop_in(users["john"][:age])
{27, %{"john" => %{}, "meg" => %{age: 23}}}
iex> users = %{john: %{age: 27}, meg: %{age: 23}}
iex> pop_in(users.john[:age])
{27, %{john: %{}, meg: %{age: 23}}}
В случае, если какой-либо элемент возвращает nil, его ключ будет удален, и удаление будет считаться успешным.
pop_in(data, keys)
Характеристики
pop_in(data, [Access.get_and_update_fun(term(), data) | term(), ...]) ::
{term(), data}
when data: Access.container() Удаляет ключ из заданной вложенной структуры.
Использует протокол Access для обхода структур в соответствии с заданным keys, если key не является функцией. Если ключ является функцией, она будет вызвана так, как указано в get_and_update_in/3.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> pop_in(users, ["john", :age])
{27, %{"john" => %{}, "meg" => %{age: 23}}}
В случае, если какой-либо элемент возвращает nil, его ключ будет удален, и удаление будет считаться успешным.
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> pop_in(users, ["jane", :age])
{nil, %{"john" => %{age: 27}, "meg" => %{age: 23}}} put_elem(tuple, index, value)
Характеристики
put_elem(tuple(), non_neg_integer(), term()) :: tuple()
Помещает value в заданный нулевой index индекс в tuple.
Встроено компилятором.
Примеры
iex> tuple = {:foo, :bar, 3}
iex> put_elem(tuple, 0, :baz)
{:baz, :bar, 3} put_in(path, value)
Помещает значение в вложенную структуру по заданному path.
Это похоже на put_in/3, за исключением того, что путь извлекается с помощью макроса, а не путем передачи списка. Например:
put_in(opts[:foo][:bar], :baz)
Эквивалентно:
put_in(opts, [:foo, :bar], :baz)
Это также работает с вложенными структурами и способом указания путей struct.path.to.value.
put_in(struct.foo.bar, :baz)
Обратите внимание, что для работы этого макроса весь путь должен всегда быть виден этому макросу. Дополнительную информацию о поддерживаемых выражениях путей см. в документации get_and_update_in/2.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users["john"][:age], 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}}
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users["john"].age, 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}} put_in(data, keys, value)
Характеристики
put_in(Access.t(), [term(), ...], term()) :: Access.t()
Помещает значение в вложенную структуру.
Использует модуль Access для обхода структур в соответствии с заданным keys, если key не является функцией. Если ключ является функцией, она будет вызвана так, как указано в get_and_update_in/3.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users, ["john", :age], 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}}
В случае, если какой-либо из элементов посередине возвращает nil, при следующей попытке доступа будет возбуждено исключение.
raise(message)
Возбуждает исключение.
Если аргумент msg является двоичным, возбуждается исключение RuntimeError с заданным аргументом в качестве сообщения.
Если msg является атомом, он просто вызывает raise/2 с атомом в качестве первого аргумента и [] в качестве второго аргумента.
Если msg является структурой исключения, она возбуждается как есть.
Если msg является чем-либо другим, raise завершится с исключением ArgumentError.
Примеры
iex> raise "oops"
** (RuntimeError) oops
try do
1 + :foo
rescue
x in [ArithmeticError] ->
IO.puts("that was expected")
raise x
end raise(exception, attributes)
Возбуждает исключение.
Вызывает функцию exception/1 по заданному аргументу (который должен быть именем модуля, как ArgumentError или RuntimeError), передавая attrs в качестве атрибутов для получения структуры исключения.
Любой модуль, содержащий вызов макроса defexception/1, автоматически реализует обратный вызов Exception.exception/1, ожидаемый raise/2. Для получения дополнительной информации см. defexception/1.
Примеры
iex> raise(ArgumentError, "Sample") ** (ArgumentError) Sample
reraise(message, stacktrace)
Возбуждает исключение, сохраняя предыдущий стек вызовов.
Работает как raise/1, но не генерирует новый стек вызовов.
Обратите внимание, что __STACKTRACE__ можно использовать внутри catch/rescue для получения текущего стека вызовов.
Примеры
try do
raise "oops"
rescue
exception ->
reraise exception, __STACKTRACE__
end reraise(exception, attributes, stacktrace)
Возбуждает исключение, сохраняя предыдущий стек вызовов.
reraise/3 работает как reraise/2, за исключением того, что аргументы передаются функции exception/1, как описано в raise/2.
Примеры
try do
raise "oops"
rescue
exception ->
reraise WrapperError, [exception: exception], __STACKTRACE__
end send(dest, message)
Характеристики
send(dest :: Process.dest(), message) :: message when message: any()
Отправляет сообщение заданному dest и возвращает сообщение.
dest может быть удаленным или локальным PID, локальным портом, локально зарегистрированным именем или кортежем в форме {registered_name, node} для зарегистрированного имени на другом узле.
Встроено компилятором.
Примеры
iex> send(self(), :hello) :hello
sigil_C(term, modifiers)
Обрабатывает сигил ~C для списков символов.
Возвращает список символов без интерполяций и без управляющих символов, за исключением экранирования символа закрывающего сигила.
Примеры
iex> ~C(foo)
'foo'
iex> ~C(f#{o}o)
'f\#{o}o' sigil_D(date_string, modifiers)
Обрабатывает сигил ~D для дат.
По умолчанию этот сигил использует встроенный Calendar.ISO, который требует, чтобы даты были записаны в формате ISO8601:
~D[yyyy-mm-dd]
например:
~D[2015-01-13]
Если вы используете альтернативные календари, можно использовать любое представление, если вы следуете за ним единственным пробелом и именем календаря:
~D[SOME-REPRESENTATION My.Alternative.Calendar]
Вариант ~d в нижнем регистре не существует, поскольку интерполяция и управляющие символы не полезны для сигилов дат.
Дополнительную информацию о датах можно найти в модуле Date.
Примеры
iex> ~D[2015-01-13] ~D[2015-01-13]
sigil_N(naive_datetime_string, modifiers)
Обрабатывает сигил ~N для неявных дат.
По умолчанию этот сигил использует встроенный Calendar.ISO, который требует, чтобы неявные даты были записаны в формате ISO8601:
~N[yyyy-mm-dd hh:mm:ss] ~N[yyyy-mm-dd hh:mm:ss.ssssss] ~N[yyyy-mm-ddThh:mm:ss.ssssss]
например:
~N[2015-01-13 13:00:07] ~N[2015-01-13T13:00:07.123]
Если вы используете альтернативные календари, может быть использовано любое представление, при условии, что за представлением следует одиночный пробел и название календаря:
~N[SOME-REPRESENTATION My.Alternative.Calendar]
Нижняя версия ~n не существует, так как интерполяция и символы экранирования не полезны для сигилов дат.
Дополнительную информацию о неявных датах можно найти в модуле NaiveDateTime.
Примеры
iex> ~N[2015-01-13 13:00:07] ~N[2015-01-13 13:00:07] iex> ~N[2015-01-13T13:00:07.001] ~N[2015-01-13 13:00:07.001]
sigil_R(term, modifiers)
Обрабатывает сигил ~R для регулярных выражений.
Возвращает шаблон регулярного выражения без интерполяции и без символов экранирования. Обратите внимание, что он по-прежнему поддерживает экранирование токенов Regex (например, экранирование + или ?) и также требует от вас экранирования закрывающего символа сигила, если он появляется в Regex.
Дополнительную информацию о регулярных выражениях можно найти в модуле Regex.
Примеры
iex> Regex.match?(~R(f#{1,3}o), "f#o")
true sigil_S(term, modifiers)
Обрабатывает сигил ~S для строк.
Возвращает строку без интерполяции и без символов экранирования, за исключением экранирования закрывающего символа сигила.
Примеры
iex> ~S(foo)
"foo"
iex> ~S(f#{o}o)
"f\#{o}o"
iex> ~S(\o/)
"\\o/"
Однако, если вы хотите повторно использовать символ сигила в строке, вам необходимо его экранировать:
iex> ~S((\)) "()"
sigil_T(time_string, modifiers)
Обрабатывает сигил ~T для времени.
По умолчанию этот сигил использует встроенный Calendar.ISO, который требует, чтобы время было записано в формате ISO8601:
~T[hh:mm:ss] ~T[hh:mm:ss.ssssss]
например:
~T[13:00:07] ~T[13:00:07.123]
Если вы используете альтернативные календари, может быть использовано любое представление, при условии, что за представлением следует одиночный пробел и название календаря:
~T[SOME-REPRESENTATION My.Alternative.Calendar]
Нижняя версия ~t не существует, так как интерполяция и символы экранирования не полезны для сигилов времени.
Дополнительную информацию о времени можно найти в модуле Time.
Примеры
iex> ~T[13:00:07] ~T[13:00:07] iex> ~T[13:00:07.001] ~T[13:00:07.001]
sigil_U(datetime_string, modifiers)
Обрабатывает сигил ~U для создания UTC DateTime.
По умолчанию этот сигил использует встроенный Calendar.ISO, который требует, чтобы UTC даты и время были записаны в формате ISO8601:
~U[yyyy-mm-dd hh:mm:ssZ] ~U[yyyy-mm-dd hh:mm:ss.ssssssZ] ~U[yyyy-mm-ddThh:mm:ss.ssssss+00:00]
например:
~U[2015-01-13 13:00:07Z] ~U[2015-01-13T13:00:07.123+00:00]
Если вы используете альтернативные календари, может быть использовано любое представление, при условии, что за представлением следует одиночный пробел и название календаря:
~U[SOME-REPRESENTATION My.Alternative.Calendar]
Указанное datetime_string должно включать смещение "Z" или "00:00", которое отмечает его как UTC, в противном случае возникает ошибка.
Нижняя версия ~u не существует, так как интерполяция и символы экранирования не полезны для сигилов дат.
Дополнительную информацию о датах и времени можно найти в модуле DateTime.
Примеры
iex> ~U[2015-01-13 13:00:07Z] ~U[2015-01-13 13:00:07Z] iex> ~U[2015-01-13T13:00:07.001+00:00] ~U[2015-01-13 13:00:07.001Z]
sigil_W(term, modifiers)
Обрабатывает сигил ~W для списка слов.
Возвращает список "слов", разделенных пробелами, без интерполяции и без символов экранирования, за исключением экранирования закрывающего символа сигила.
Модификаторы
-
s: слова в списке являются строками (по умолчанию) -
a: слова в списке являются атомами -
c: слова в списке являются списками символов
Примеры
iex> ~W(foo #{bar} baz)
["foo", "\#{bar}", "baz"] sigil_c(term, modifiers)
Обрабатывает сигил ~c для списков символов.
Возвращает список символов как если бы это была строка в одинарных кавычках, снимая экранирование символов и заменяя интерполяции.
Примеры
iex> ~c(foo)
'foo'
iex> ~c(f#{:o}o)
'foo'
iex> ~c(f\#{:o}o)
'f\#{:o}o' sigil_r(term, modifiers)
Обрабатывает сигил ~r для регулярных выражений.
Возвращает шаблон регулярного выражения, снимая экранирование символов и заменяя интерполяции.
Дополнительную информацию о регулярных выражениях можно найти в модуле Regex.
Примеры
iex> Regex.match?(~r(foo), "foo") true iex> Regex.match?(~r/abc/, "abc") true
sigil_s(term, modifiers)
Обрабатывает сигил ~s для строк.
Возвращает строку как если бы это была строка в двойных кавычках, снимая экранирование символов и заменяя интерполяции.
Примеры
iex> ~s(foo)
"foo"
iex> ~s(f#{:o}o)
"foo"
iex> ~s(f\#{:o}o)
"f\#{:o}o" sigil_w(term, modifiers)
Обрабатывает сигил ~w для списка слов.
Возвращает список "слов", разделенных пробелами. Экранирование символов и интерполяция происходят для каждого слова.
Модификаторы
-
s: слова в списке являются строками (по умолчанию) -
a: слова в списке являются атомами -
c: слова в списке являются списками символов
Примеры
iex> ~w(foo #{:bar} baz)
["foo", "bar", "baz"]
iex> ~w(foo #{" bar baz "})
["foo", "bar", "baz"]
iex> ~w(--source test/enum_test.exs)
["--source", "test/enum_test.exs"]
iex> ~w(foo bar baz)a
[:foo, :bar, :baz] spawn(fun)
Specs
spawn((() -> any())) :: pid()
Запускает заданную функцию и возвращает ее PID.
Обычно разработчики не используют функции spawn, а вместо этого используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
См. модуль Process для получения дополнительной информации о функциях, связанных с процессами.
Анонимная функция получает 0 аргументов и может возвращать любое значение.
Встраивается компилятором.
Примеры
current = self()
child = spawn(fn -> send(current, {self(), 1 + 2}) end)
receive do
{^child, 3} -> IO.puts("Received 3 back")
end spawn(module, fun, args)
Specs
spawn(module(), atom(), list()) :: pid()
Запускает заданную функцию fun из заданного module, передавая ей заданные args и возвращает ее PID.
Обычно разработчики не используют функции spawn, а вместо этого используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
См. модуль Process для получения дополнительной информации о функциях, связанных с процессами.
Встраивается компилятором.
Примеры
spawn(SomeModule, :function, [1, 2, 3])
spawn_link(fun)
Specs
spawn_link((() -> any())) :: pid()
Запускает заданную функцию, связывает ее с текущим процессом и возвращает ее PID.
Обычно разработчики не используют функции spawn, а вместо этого используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
См. модуль Process для получения дополнительной информации о функциях, связанных с процессами. Для получения более подробной информации о связывании, см. Process.link/1.
Анонимная функция получает 0 аргументов и может возвращать любое значение.
Встраивается компилятором.
Примеры
current = self()
child = spawn_link(fn -> send(current, {self(), 1 + 2}) end)
receive do
{^child, 3} -> IO.puts("Received 3 back")
end spawn_link(module, fun, args)
Specs
spawn_link(module(), atom(), list()) :: pid()
Запускает заданную функцию fun из заданного module, передавая ей заданные args, связывает ее с текущим процессом и возвращает ее PID.
Обычно разработчики не используют функции spawn, а вместо этого используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
См. модуль Process для получения дополнительной информации о функциях, связанных с процессами. Для получения более подробной информации о связывании, см. Process.link/1.
Встраивается компилятором.
Примеры
spawn_link(SomeModule, :function, [1, 2, 3])
spawn_monitor(fun)
Характеристики
spawn_monitor((() -> any())) :: {pid(), reference()} Запускает заданную функцию, отслеживает её и возвращает её PID и ссылку на отслеживание.
Обычно разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством в плане интроспекции и отладки.
См. модуль Process для получения дополнительных функций, связанных с процессами.
Анонимная функция принимает 0 аргументов и может возвращать любое значение.
Встроено компилятором.
Примеры
current = self()
spawn_monitor(fn -> send(current, {self(), 1 + 2}) end) spawn_monitor(module, fun, args)
Характеристики
spawn_monitor(module(), atom(), list()) :: {pid(), reference()} Запускает указанный модуль и функцию, передавая заданные аргументы, отслеживает его и возвращает его PID и ссылку на отслеживание.
Обычно разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством в плане интроспекции и отладки.
См. модуль Process для получения дополнительных функций, связанных с процессами.
Встроено компилятором.
Примеры
spawn_monitor(SomeModule, :function, [1, 2, 3])
struct(struct, fields \\ [])
Характеристики
struct(module() | struct(), Enum.t()) :: struct()
Создаёт и обновляет структуру.
Аргумент struct может быть атомом (который определяет defstruct) или собственно структурой struct. Второй аргумент — любой Enumerable, который генерирует двухэлементные кортежи (пары ключ-значение) при перечислении.
Ключи в Enumerable, которые не существуют в структуре, автоматически отбрасываются. Обратите внимание, что ключи должны быть атомами, поскольку только атомы разрешены при определении структуры. Если ключи в Enumerable дублируются, будет взят последний элемент (тот же механизм, что и в Map.new/1).
Эта функция полезна для динамического создания и обновления структур, а также для преобразования карт в структуры; в последнем случае просто вставка соответствующего поля :__struct__ в карту может быть недостаточно, и следует использовать struct/2 вместо этого.
Примеры
defmodule User do
defstruct name: "john"
end
struct(User)
#=> %User{name: "john"}
opts = [name: "meg"]
user = struct(User, opts)
#=> %User{name: "meg"}
struct(user, unknown: "value")
#=> %User{name: "meg"}
struct(User, %{name: "meg"})
#=> %User{name: "meg"}
# String keys are ignored
struct(User, %{"name" => "meg"})
#=> %User{name: "john"} struct!(struct, fields \\ [])
Характеристики
struct!(module() | struct(), Enum.t()) :: struct()
Аналогично struct/2, но проверяет корректность ключей.
Функция struct!/2 эмулирует поведение структур на этапе компиляции. Это означает, что:
при создании структуры, как в
struct!(SomeStruct, key: :value), она эквивалентна%SomeStruct{key: :value}, и поэтому эта функция проверит, принадлежит ли каждая пара ключ-значение структуре. Если структура требует каких-либо ключей через@enforce_keys, они также будут проверены;при обновлении структуры, как в
struct!(%SomeStruct{}, key: :value), она эквивалентна%SomeStruct{struct | key: :value}, и поэтому эта функция проверит, принадлежит ли каждая пара ключ-значение структуре. Однако при обновлении структур ключи не проверяются, так как они проверяются только при создании;
throw(term)
Характеристики
throw(term()) :: no_return()
Нелокальный возврат из функции.
См. Kernel.SpecialForms.try/1 для получения дополнительной информации.
Встроено компилятором.
to_charlist(term)
Преобразует заданный термин в список символов в соответствии с протоколом List.Chars.
Примеры
iex> to_charlist(:foo) 'foo'
to_string(term)
Преобразует аргумент в строку в соответствии с протоколом String.Chars.
Это функция, вызываемая при интерполяции строк.
Примеры
iex> to_string(:foo) "foo"
unless(condition, clauses)
Обеспечивает макрос unless.
Этот макрос оценивает и возвращает блок do, переданный во втором аргументе, если condition оценивается как ложное значение (false или nil). В противном случае он возвращает значение блока else, если он присутствует, или nil, если нет.
См. также if/2.
Примеры
iex> unless(Enum.empty?([]), do: "Hello") nil iex> unless(Enum.empty?([1, 2, 3]), do: "Hello") "Hello" iex> unless Enum.sum([2, 2]) == 5 do ...> "Math still works" ...> else ...> "Math is broken" ...> end "Math still works"
update_in(path, fun)
Обновляет вложенную структуру с помощью заданной path.
Это аналогично update_in/3, за исключением того, что путь извлекается с помощью макроса, а не передаётся в виде списка. Например:
update_in(opts[:foo][:bar], &(&1 + 1))
Эквивалентно:
update_in(opts, [:foo, :bar], &(&1 + 1))
Это также работает со вложенными структурами и способом указания путей через struct.path.to.value.
update_in(struct.foo.bar, &(&1 + 1))
Обратите внимание, что для работы этого макроса весь путь должен быть виден этому макросу. Дополнительную информацию о поддерживаемых выражениях пути см. в документации get_and_update_in/2.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users["john"][:age], &(&1 + 1))
%{"john" => %{age: 28}, "meg" => %{age: 23}}
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users["john"].age, &(&1 + 1))
%{"john" => %{age: 28}, "meg" => %{age: 23}} update_in(data, keys, fun)
Характеристики
update_in(Access.t(), [term(), ...], (term() -> term())) :: Access.t()
Обновляет ключ во вложенной структуре.
Использует модуль Access для обхода структур в соответствии с заданным keys, если key не является функцией. Если ключ является функцией, он будет вызван в соответствии с get_and_update_in/3.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users, ["john", :age], &(&1 + 1))
%{"john" => %{age: 28}, "meg" => %{age: 23}}
Если какой-либо из промежуточных элементов возвращает nil, при попытке доступа к нему в дальнейшем будет выброшено исключение.
use(module, opts \\ [])
Использует указанный модуль в текущем контексте.
При вызове:
use MyModule, some: :options
макрос __using__/1 из модуля MyModule вызывается со вторым аргументом, переданным в use, в качестве его аргумента. Поскольку __using__/1 является макросом, применяются все обычные правила макросов, и его возвращаемое значение должно быть кодом с цитированием, который затем вставляется в место вызова use/2.
Примеры
Например, для написания тестовых случаев с использованием фреймворка ExUnit, предоставляемого с Elixir, разработчик должен использовать модуль ExUnit.Case:
defmodule AssertionTest do
use ExUnit.Case, async: true
test "always pass" do
assert true
end
end
В этом примере ExUnit.Case.__using__/1 вызывается со списком ключевых слов [async: true] в качестве аргумента; use/2 преобразуется в:
defmodule AssertionTest do
require ExUnit.Case
ExUnit.Case.__using__(async: true)
test "always pass" do
assert true
end
end
ExUnit.Case затем определит макрос __using__/1.
defmodule ExUnit.Case do
defmacro __using__(opts) do
# do something with opts
quote do
# return some code to inject in the caller
end
end
end
Рекомендации по применению
__using__/1 обычно используется, когда необходимо установить некоторое состояние (через атрибуты модуля) или обратные вызовы (например, @before_compile, см. документацию Module для получения дополнительной информации) в вызывающий модуль.
__using__/1 также может использоваться для псевдонимизации, импорта или требуемого функционала из различных модулей:
defmodule MyModule do
defmacro __using__(_opts) do
quote do
import MyModule.Foo
import MyModule.Bar
import MyModule.Baz
alias MyModule.Repo
end
end
end
Однако, не предоставляйте __using__/1 если всё, что оно делает, это импорт, псевдонимизация или требование самого модуля. Например, избегайте этого:
defmodule MyModule do
defmacro __using__(_opts) do
quote do
import MyModule
end
end
end
В таких случаях разработчики должны вместо этого напрямую импортировать или псевдонимизировать модуль, чтобы они могли настроить его по своему усмотрению без косвенности через use/2.
Наконец, разработчики также должны избегать определения функций внутри обратного вызова __using__/1, если эти функции не являются стандартной реализацией ранее определённого @callback или не предназначены для переопределения (см. defoverridable/1). Даже в этих случаях определение функций должно рассматриваться как «последний вариант».
Если вы хотите предоставить некоторую существующую функциональность модулю пользователя, определите её в модуле, который будет импортироваться соответствующим образом; например, ExUnit.Case не определяет макрос test/3 в модуле, который вызывает use ExUnit.Case, но определяет ExUnit.Case.test/3 и просто импортирует его в вызывающий модуль при использовании.
var!(var, context \\ nil)
При использовании внутри цитирования помечает, что данная переменная не должна подвергаться гигиене.
Аргументом может быть нецитируемая переменная или кортеж стандартного вида {name, meta, context}.
См. Kernel.SpecialForms.quote/2 для получения дополнительной информации.
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.10.4/Kernel.html