Ядро
Kernel — это стандартная среда выполнения Elixir.
Она в основном состоит из:
- базовых языковых примитивов, таких как арифметические операторы, создание процессов, обработка типов данных и т. д.
- макросов для управления потоком и определения новых функций (модули, функции и так далее)
- условий для расширения сопоставления с образцом
Вы можете использовать функции/макросы Kernel без префикса Kernel в любом месте кода Elixir, так как все его функции и макросы автоматически импортируются. Например, в 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— коллекции фиксированного числа элементов
Существует два типа данных без сопровождающего модуля:
- Битовый массив — последовательность битов, созданная с помощью
Kernel.SpecialForms.<<>>/1. Когда количество битов делится на 8, они называются двоичными и могут быть обработаны с помощью модуля Erlang:binary - Ссылка — уникальное значение в системе выполнения, созданное с помощью
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— преобразует типы данных в их представление во внешнем мире как списки символов (не основанные на программировании) -
String.Chars— преобразует типы данных в их представление во внешнем мире как строки (не основанные на программировании)
Функциональность, основанная на процессах и ориентированная на приложения
Следующие модули построены на основе процессов, чтобы обеспечить конкуретность, отказоустойчивость и многое другое.
-
Agent— процесс, который инкапсулирует изменяемое состояние -
Application— функции для запуска, остановки и настройки приложений -
GenServer— универсальный API клиент-сервер -
Registry— хранилище ключ-значение на основе процессов -
Supervisor— процесс, отвечающий за запуск, надзор и остановку других процессов -
Task— процесс, выполняющий вычисления -
Task.Supervisor— супервайзор для управления задачами исключительно
Дополнительные документы
Документация Elixir также включает дополнительные документы в разделе «Страницы». Это:
- Совместимость и устаревшие функции — список совместимости между версиями Elixir и Erlang/OTP, схема выпусков; перечисляет все устаревшие функции, когда они были устаревшими и альтернативы
- Условные выражения — введение в условные выражения и расширения
- Руководство по библиотекам — общие рекомендации, антипаттерны и правила для тех, кто создаёт библиотеки
- Правила именования — правила именования для кода Elixir
- Операторы — список всех операторов Elixir и их приоритетов
- Справочник по синтаксису — справочник по синтаксису языка
- Типовые спецификации — типы и спецификации функций, включая список типов
- Синтаксис Юникода — описание поддержки Elixir Юникода
- Написание документации — руководство по написанию документации на Elixir
Условные выражения
Этот модуль включает встроенные условные выражения, используемые разработчиками Elixir. Это предопределённый набор функций и макросов, которые дополняют сопоставление с образцом, обычно вызываемый после оператора when. Например:
def drive(%User{age: age}) when age >= 16 do
...
end Этот фрагмент кода будет выполнен только в том случае, если возраст пользователя не менее 16 лет. Более полное введение в условные выражения доступно на странице Условные выражения.
Инлайнинг
Некоторые из функций, описанных в этом модуле, инлайнятся компилятором 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_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_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
Читает и записывает атрибуты текущего модуля.
- 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
Оператор конвейера.
- left || right
Предоставляет оператор короткого замыкания, который вычисляет и возвращает второе выражение только в том случае, если первое выражение не оценивается как истинное значение (то есть, оно либо
nil, либоfalse). В противном случае возвращает первое выражение.
Защиты
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
Спецификации
+value :: value when value: number()
Арифметическое унарное сложение.
Разрешено в тестах защит. Встраивается компилятором.
Примеры
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)
Спецификации
elem(tuple(), non_neg_integer()) :: term()
Возвращает элемент по нулевому индексу index в tuple.
Вызывает ArgumentError, когда индекс отрицательный или выходит за пределы диапазона элементов кортежа.
Разрешено в тестах guard. Встраивается компилятором.
Примеры
tuple = {:foo, :bar, 3}
elem(tuple, 1)
#=> :bar
elem({}, 0)
#=> ** (ArgumentError) argument error
elem({:foo, :bar}, 2)
#=> ** (ArgumentError) argument error floor(number)
Спецификации
floor(number()) :: integer()
Возвращает наибольшее целое число, меньшее или равное number.
Если вы хотите выполнить операцию floor для других десятичных знаков, используйте Float.floor/2.
Разрешено в тестах guard. Встраивается компилятором.
hd(list)
Спецификации
hd(nonempty_maybe_improper_list(elem, any())) :: elem when elem: term()
Возвращает головной элемент списка. Вызывает ArgumentError, если список пуст.
Работает с некорректными списками.
Разрешено в тестах guard. Встраивается компилятором.
Примеры
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) может использоваться в предложениях guard, если правая часть является диапазоном или списком. В таких случаях Elixir развернет оператор в допустимое выражение guard. Например:
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)
Спецификации
is_atom(term()) :: boolean()
Возвращает true, если term является атомом; в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
is_binary(term)
Спецификации
is_binary(term()) :: boolean()
Возвращает true, если term является бинарным; в противном случае возвращает false.
Бинарный файл всегда содержит целое число байтов.
Разрешено в тестах guard. Встраивается компилятором.
Примеры
iex> is_binary("foo")
true
iex> is_binary(<<1::3>>)
false is_bitstring(term)
Спецификации
is_bitstring(term()) :: boolean()
Возвращает true, если term является битовой строкой (включая бинарный файл); в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
Примеры
iex> is_bitstring("foo")
true
iex> is_bitstring(<<1::3>>)
true is_boolean(term)
Спецификации
is_boolean(term()) :: boolean()
Возвращает true, если term является атомом true или атомом false (т.е. булевым значением); в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
is_float(term)
Спецификации
is_float(term()) :: boolean()
Возвращает true, если term является числом с плавающей точкой; в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
is_function(term)
Спецификации
is_function(term()) :: boolean()
Возвращает true, если term является функцией; в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
is_function(term, arity)
Спецификации
is_function(term(), non_neg_integer()) :: boolean()
Возвращает true, если term является функцией, которая может быть применена с arity числом аргументов; в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
Примеры
iex> is_function(fn x -> x * 2 end, 1) true iex> is_function(fn x -> x * 2 end, 2) false
is_integer(term)
Спецификации
is_integer(term()) :: boolean()
Возвращает true, если term является целым числом; в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
is_list(term)
Спецификации
is_list(term()) :: boolean()
Возвращает true, если term является списком с нулем или более элементами; в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
is_map(term)
Спецификации
is_map(term()) :: boolean()
Возвращает true, если term является картой; в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
is_nil(term)
Возвращает true, если term является nil, false в противном случае.
Разрешено в предложениях guard.
Примеры
iex> is_nil(1) false iex> is_nil(nil) true
is_number(term)
Спецификации
is_number(term()) :: boolean()
Возвращает true, если term является целым или числом с плавающей точкой; в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
is_pid(term)
Спецификации
is_pid(term()) :: boolean()
Возвращает true, если term является PID (идентификатором процесса); в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
is_port(term)
Спецификации
is_port(term()) :: boolean()
Возвращает true, если term является идентификатором порта; в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
is_reference(term)
Спецификации
is_reference(term()) :: boolean()
Возвращает true, если term является ссылкой; в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
is_tuple(term)
Спецификации
is_tuple(term()) :: boolean()
Возвращает true, если term является кортежем; в противном случае возвращает false.
Разрешено в тестах guard. Встраивается компилятором.
length(list)
Спецификации
length(list()) :: non_neg_integer()
Возвращает длину list.
Разрешено в тестах guard. Встраивается компилятором.
Примеры
iex> length([1, 2, 3, 4, 5, 6, 7, 8, 9]) 9
map_size(map)
Спецификации
map_size(map()) :: non_neg_integer()
Возвращает размер карты.
Размер карты — это количество пар ключ-значение, которые содержит карта.
Эта операция выполняется за постоянное время.
Разрешено в тестах guard. Встраивается компилятором.
Примеры
iex> map_size(%{a: "foo", b: "bar"})
2 node()
Спецификации
node() :: node()
Возвращает атом, представляющий имя локального узла. Если узел не активен, вместо этого возвращается :nonode@nohost.
Разрешено в тестах guard. Встраивается компилятором.
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(float()) :: integer()
round(value) :: value when value: 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(value) :: value when value: integer()
trunc(float()) :: 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 Функции
!значение
Логическое отрицание.
Принимает любой аргумент (не только булевы значения) и возвращает true если аргумент является false или nil; в противном случае возвращает false.
Запрещено в условиях защиты.
Примеры
iex> !Enum.empty?([]) false iex> !List.first([]) true
левая && правая
Обеспечивает оператор короткого замыкания, который вычисляет и возвращает второе выражение только если первое выражение имеет истинное значение (ни 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, этот оператор принимает любое выражение в качестве первого аргумента, а не только булевы значения.
левая ++ правая
Характеристики
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]
левая -- правая
Характеристики
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 целыми числами.
Если последний больше, чем первый, диапазон будет возрастать от первого к последнему. Если первый больше, чем последний, диапазон будет убывать от первого к последнему. Если первый равен последнему, диапазон будет содержать один элемент, который является самим числом.
Примеры
iex> 0 in 1..3 false iex> 1 in 1..3 true iex> 2 in 1..3 true iex> 3 in 1..3 true
левая <> правая
Конкатенирует две двоичные строки.
Примеры
iex> "foo" <> "bar" "foobar"
Оператор <>/2 также может использоваться в сопоставлении с образцом (и условиях защиты), если левый аргумент является литеральной двоичной строкой:
iex> "foo" <> x = "foobar" iex> x "bar"
x <> "bar" = "foobar" привело бы к исключению CompileError.
левая =~ правая
Характеристики
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
@выражение
Читает и записывает атрибуты текущего модуля.
Каноническим примером атрибутов является аннотация, что модуль реализует поведение 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 для получения других функций для управления атрибутами модуля.
alias!(псевдоним)
При использовании внутри цитирования отмечает, что заданный псевдоним не должен подвергаться санизации. Это означает, что псевдоним будет расширен при разворачивании макроса.
См. Kernel.SpecialForms.quote/2 для получения дополнительной информации.
apply(функция, аргументы)
Характеристики
apply((... -> any()), [any()]) :: any()
Вызывает заданную анонимную функцию fun со списком аргументов args.
Встроенный компилятором.
Примеры
iex> apply(fn x -> x * 2 end, [2]) 4
apply(модуль, имя_функции, аргументы)
Характеристики
apply(module(), function_name :: atom(), [any()]) :: any()
Вызывает заданную функцию из module со списком аргументов args.
apply/3 используется для вызова функций, где модуль, имя функции или аргументы определяются динамически во время выполнения. По этой причине вы не можете вызывать макросы с помощью apply/3, только функции.
Встроенный компилятором.
Примеры
iex> apply(Enum, :reverse, [[1, 2, 3]]) [3, 2, 1]
binding(контекст \\ 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(вызов, выражение \\ 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— получает структуру исключения и должна вернуть её сообщение. Чаще всего исключения имеют поле сообщения, к которому по умолчанию обращается эта функция. Однако, если исключение не имеет поля сообщения, эта функция должна быть явно реализована.
Поскольку исключения являются структурами, 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 - имя модуля
- двоичное содержимое модуля
- результат вычисления блока содержимого
Примеры
iex> defmodule Foo do ...> def bar, do: :baz ...> end iex> Foo.bar() :baz
Вложенность
Вложенность модуля внутри другого модуля влияет на имя вложенного модуля:
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) #=> 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равно null, возвращаетсяnil -
foo.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 будет возвращено в соответствии с модулем Access:
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, 2)
false
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 по указанному индексу (от нуля) в 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 для дат.
Нижний регистр ~d не существует, так как интерполяция и экранирование не нужны для сигилов дат.
Дополнительная информация о датах находится в модуле Date.
Примеры
iex> ~D[2015-01-13] ~D[2015-01-13]
sigil_N(naive_datetime_string, modifiers)
Обрабатывает сигил ~N для «неявных» дат и времени.
Нижний регистр ~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.
Примеры
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 для времени.
Нижний регистр ~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.
Нижний регистр ~u не существует, так как интерполяция и экранирование не нужны для сигилов дат и времени.
Указанная datetime_string должна содержать "Z" или смещение "00:00", обозначающие UTC, иначе произойдёт ошибка.
Дополнительная информация о датах и времени находится в модуле 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)
Характеристики
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)
Характеристики
spawn(module(), atom(), list()) :: pid()
Запускает заданную функцию fun из данного module, передавая ей заданные args, и возвращает её PID.
Обычно разработчики не используют функции spawn, а вместо этого используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
См. модуль Process для получения дополнительной информации о функциях, связанных с процессами.
Встраивается компилятором.
Примеры
spawn(SomeModule, :function, [1, 2, 3])
spawn_link(fun)
Характеристики
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)
Характеристики
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) или самой структурой. Второй аргумент — любой Enumerable, который во время перечисления выводит кортежи из двух элементов (пар ключ-значение).
Ключи в Enumerable, которые не существуют в структуре, автоматически отбрасываются. Обратите внимание, что ключи должны быть атомами, так как только атомы допускаются при определении структуры.
Эта функция полезна для динамического создания и обновления структур, а также для преобразования карт в структуры; в последнем случае, просто вставка соответствующего :__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, разработчик должен use модуль 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 для получения дополнительной информации.
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). В противном случае возвращает первое выражение.
Запрещено в клаузах guard.
Примеры
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, этот оператор принимает любое выражение в качестве первого аргумента, а не только булевы значения.
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.9.4/Kernel.html