Ядро
Kernel является стандартной средой Elixir.
Она в основном состоит из:
- базовых языковых примитивов, таких как арифметические операторы, создание процессов, обработка типов данных и другие
- макросов для управления потоком и определения новой функциональности (модули, функции и т. п.)
- проверок guard для дополнения сопоставления с образцом
Вы можете вызывать функции и макросы Kernel в любом месте кода Elixir без использования префикса Kernel., так как они все автоматически импортированы. Например, в IEx вы можете вызвать:
iex> is_number(13) true
Если вы не хотите импортировать функцию или макрос из Kernel, используйте опцию :except и затем перечислите функцию/макрос по арности:
import Kernel, except: [if: 2, unless: 2]
См. Kernel.SpecialForms.import/2 для получения дополнительной информации об импорте.
Elixir также имеет специальные формы, которые всегда импортируются и не могут быть пропущены. Они описаны в Kernel.SpecialForms.
Стандартная библиотека
Kernel предоставляет базовые возможности, на которых построена стандартная библиотека Elixir. Рекомендуется изучить стандартную библиотеку для получения расширенной функциональности. Ниже приведены основные группы модулей в стандартной библиотеке (этот список не является полным справочником, см. колонку документации для всех записей).
Встроенные типы
Следующие модули обрабатывают встроенные типы данных Elixir:
-
Atom- литеральные константы с именем (true,false, иnil— атомы) -
Float- числа с плавающей точкой -
Function- ссылка на фрагмент кода, созданный с помощью специальной формыfn/1 -
Integer- целые числа (без дробных частей) -
List- коллекции переменного количества элементов (связанные списки) -
Map- коллекции пар ключ-значение -
Process- лёгкие потоки выполнения -
Port- механизмы взаимодействия с внешним миром -
Tuple- коллекции фиксированного количества элементов
Существуют два типа данных без сопровождающего модуля:
- Битовый массив — последовательность битов, созданная с помощью
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. Они являются контрактами, реализуемыми типами данных. См. Protocol для получения дополнительной информации о протоколах. В стандартной библиотеке Elixir представлены следующие протоколы:
-
Collectable- собирает данные в тип данных -
Enumerable- обрабатывает коллекции в Elixir. МодульEnumпредоставляет жадные функции для работы с коллекциями, а модульStream— ленивые. -
Inspect- преобразует типы данных в их представление на языке программирования -
List.Chars- преобразует типы данных в их представление для внешнего мира в виде списков символов (не базирующееся на программировании) -
String.Chars- преобразует типы данных в их представление для внешнего мира в виде строк (не базирующееся на программировании)
Функциональность, ориентированная на процессы и приложения
Следующие модули строятся на основе процессов для обеспечения конкурентности, отказоустойчивости и многого другого.
-
Agent- процесс, инкапсулирующий изменяемое состояние -
Application- функции для запуска, остановки и настройки приложений -
GenServer- общий API клиент-сервер -
Registry- хранилище ключ-значение на основе процессов -
Supervisor- процесс, отвечающий за запуск, контроль и остановку других процессов -
Task- процесс, выполняющий вычисления -
Task.Supervisor- supervisor для управления исключительно задачами
Дополнительная документация
Документация Elixir также включает вспомогательные документы в разделе "Страницы". Это:
- Совместимость и устаревание - перечисляет совместимость между каждой версией Elixir и Erlang/OTP, схему релизов; перечисляет все устаревшие функции, когда они устарели и альтернативы
- Рекомендации по библиотекам - общие рекомендации, антипаттерны и правила для разработчиков библиотек
- Правила именования - правила именования для кода Elixir
- Операторы - перечисляет все операторы Elixir и их приоритеты
- Шаблоны и гварды - введение в шаблоны, гварды и расширения
- Справочник синтаксиса - справочник синтаксиса языка
- Типоспецификации- типы и спецификации функций, включая список типов
- Синтаксис Unicode - описывает поддержку Unicode в Elixir
- Написание документации - рекомендации по написанию документации в Elixir
Гварды
Этот модуль содержит встроенные гварды, используемые разработчиками Elixir. Они представляют собой предопределенный набор функций и макросов, которые дополняют сопоставление с образцом, обычно вызываемые после оператора when. Например:
def drive(%User{age: age}) when age >= 16 do
...
end
Данный условный оператор будет вызван только если возраст пользователя больше или равен 16. Гварды также поддерживают объединение нескольких условий с and и or. Весь гвард считается истинным, если все выражения гварда примут значение true. Более подробное введение в гварды доступно на странице Шаблоны и гварды.
Структурное сравнение
Функции сравнения в этом модуле выполняют структурное сравнение. Это означает, что структуры сравниваются на основе их представления, а не на их семантическом значении. Это особенно важно для функций, предназначенных для предоставления упорядочивания, таких как >/2, </2, >=/2, <=/2, min/2 и max/2. Например:
~D[2017-03-31] > ~D[2017-04-01]
вернёт true, потому что структурное сравнение сравнивает поле :day до :month или :year. Поэтому при сравнении структур часто используется функция compare/2, предоставляемая самими модулями структур:
iex> Date.compare(~D[2017-03-31], ~D[2017-04-01]) :lt
В качестве альтернативы вы можете использовать функции модуля Enum для сортировки или вычисления максимума/минимума:
iex> Enum.sort([~D[2017-03-31], ~D[2017-04-01]], Date) [~D[2017-03-31], ~D[2017-04-01]] iex> Enum.max([~D[2017-03-31], ~D[2017-04-01]], Date) ~D[2017-04-01]
Истинностные и ложные значения
Помимо булевых значений 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
Инлайнирование
Некоторые из функций, описанных в этом модуле, встроенные в компиляторе Elixir в их аналоги на Erlang в модуле :erlang. Эти функции называются BIF (встроенные внутренние функции) в Erlang и они обладают интересными свойствами, так как некоторые из них разрешены в охраняющих условиях, а другие используются для оптимизации компилятора.
Большинство встроенных функций можно увидеть в действии при захвате функции:
iex> &Kernel.is_atom/1 &:erlang.is_atom/1
Эти функции будут явно помечены в их документации как "встроенные компилятором".
Краткое описание
Охраняющие условия
- left * right
Оператор умножения.
- +value
Унарный оператор сложения.
- left + right
Оператор сложения.
- -value
Унарный оператор вычитания.
- left - right
Оператор вычитания.
- left / right
Оператор деления.
- left != right
Оператор неравенства.
- left !== right
Оператор строгого неравенства.
- left < right
Оператор меньше.
- left <= right
Оператор меньше или равно.
- left == right
Оператор равенства. Возвращает
trueесли два значения равны.- left === right
Оператор строгого равенства.
- left > right
Оператор больше.
- 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_exception(term)
Возвращает true, если
termявляется исключением; в противном случае возвращаетfalse.- is_exception(term, name)
Возвращает true, если
termявляется исключением типаname; в противном случае возвращаетfalse.- is_float(term)
Возвращает
trueеслиtermэто число с плавающей точкой; в противном случае возвращаетfalse.- is_function(term)
Возвращает
trueеслиtermэто функция; в противном случае возвращаетfalse.- is_function(term, arity)
Возвращает
trueеслиtermэто функция, которая может быть применена сarityаргументами; в противном случае возвращаетfalse.- is_integer(term)
Возвращает
trueеслиtermэто целое число; в противном случае возвращаетfalse.- is_list(term)
Возвращает
trueеслиtermэто список с нулем или более элементами; в противном случае возвращаетfalse.- is_map(term)
Возвращает
trueеслиtermэто карта; в противном случае возвращаетfalse.- is_map_key(map, key)
Возвращает
trueеслиkeyэто ключ вmap; в противном случае возвращаетfalse.- is_nil(term)
Возвращает
trueеслиtermэтоnil;falseв противном случае.- is_number(term)
Возвращает
trueеслиtermэто целое или вещественное число; в противном случае возвращаетfalse.- is_pid(term)
Возвращает
trueеслиtermэто PID (идентификатор процесса); в противном случае возвращаетfalse.- is_port(term)
Возвращает
trueеслиtermэто идентификатор порта; в противном случае возвращаетfalse.- is_reference(term)
Возвращает
trueеслиtermэто ссылка; в противном случае возвращаетfalse.- is_struct(term)
Возвращает true, если
termэто структура; в противном случае возвращаетfalse.- is_struct(term, name)
Возвращает true, если
termэто структура типаname; в противном случае возвращаетfalse.
- is_tuple(term)
Возвращает
true, еслиtermэто кортеж; в противном случае возвращаетfalse.
- length(list)
Возвращает длину списка.
- map_size(map)
Возвращает размер карты.
- node()
Возвращает атом, представляющий имя локального узла. Если узел не активен, вместо этого возвращается
0..-1//1.- node(arg)
Возвращает узел, где находится заданный аргумент. Аргумент может быть PID, ссылкой или портом. Если локальный узел не активен, возвращается
first.- not value
Строго булевый оператор "not".
- left or right
Строго булевый оператор "or".
- rem(dividend, divisor)
Вычисляет остаток от целочисленного деления.
- round(number)
Округляет число до ближайшего целого.
- self()
Возвращает PID (идентификатор процесса) вызывающего процесса.
- tl(list)
Возвращает хвост списка. Вызывает
ArgumentError, если список пуст.- trunc(number)
Возвращает целую часть числа.
- tuple_size(tuple)
Возвращает размер кортежа.
Функции
- left && right
Булевый оператор "и".
- base ** exponent
Оператор возведения в степень.
- left ++ right
Оператор конкатенации списков. Конкатенирует список справа и элемент слева, возвращая список.
- left -- right
Оператор вычитания списков. Удаляет первое вхождение элемента справа из списка слева для каждого элемента справа.
- ..
Создаёт диапазон срезов
0..-1//1.- first..last
Создаёт диапазон от
firstдоlast.- first..last//step
Создаёт диапазон от
firstдоlastс шагомstep.- !value
Булевый оператор "не".
- left <> right
Оператор бинарной конкатенации. Конкатенирует два бинарных числа.
- left =~ right
Оператор соответствия по тексту. Сопоставляет термин слева с регулярным выражением или строкой справа.
- @expr
Унарный оператор атрибута модуля.
- alias!(alias)
Когда используется внутри кавычек, отмечает, что данный псевдоним не должен быть санизирован. Это означает, что псевдоним будет расширен при расширении макроса.
- apply(fun, args)
Вызывает заданную анонимную функцию
funсо списком аргументовargs.- apply(module, function_name, args)
Вызывает заданную функцию из
moduleсо списком аргументовargs.- binary_slice(binary, range)
Возвращает бинарное значение с позиции начала диапазона до позиции конца диапазона.
- binary_slice(binary, start, size)
Возвращает бинарное значение, начиная с позиции
startи заданного размераsize.- binding(context \\ nil)
Возвращает привязку для данного контекста в виде списка ключевых слов.
- dbg(code \\ quote do binding() end, options \\ [])
Отлаживает заданный
code.- 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)
Возвращает наибольший из двух заданных терминов в соответствии с их структурным сравнением.
- min(first, second)
Возвращает наименьший из двух заданных терминов в соответствии с их структурным сравнением.
- pop_in(path)
Удаляет ключ из вложенной структуры по заданному
path.- pop_in(data, keys)
Удаляет ключ из данной вложенной структуры.
- put_elem(tuple, index, value)
Заменяет значение
valueна заданную позицию с нулевой базойindexв кортежеtuple.
- put_in(path, value)
Размещает значение во вложенной структуре по заданному пути.
- put_in(data, keys, value)
Размещает значение во вложенную структуру.
- raise(message)
Вызывает исключение.
- raise(exception, attributes)
Вызывает исключение.
- reraise(message, stacktrace)
Вызывает исключение, сохраняя предыдущий стек вызовов.
- reraise(exception, attributes, stacktrace)
Вызывает исключение, сохраняя предыдущий стек вызовов.
- send(dest, message)
Отправляет сообщение заданному объекту и возвращает полученное сообщение.
- sigil_C(term, modifiers)
Обрабатывает сигил для списков символов.
- sigil_c(term, modifiers)
Обрабатывает сигил для списков символов.
- sigil_D(date_string, modifiers)
Обрабатывает сигил для дат.
- sigil_N(naive_datetime_string, modifiers)
Обрабатывает сигил для неявных дат и времени.
- sigil_R(term, modifiers)
Обрабатывает сигил для регулярных выражений.
- sigil_r(term, modifiers)
Обрабатывает сигил для регулярных выражений.
- sigil_S(term, modifiers)
Обрабатывает сигил для строк.
- sigil_s(term, modifiers)
Обрабатывает сигил для строк.
- sigil_T(time_string, modifiers)
Обрабатывает сигил для временных значений.
- sigil_U(datetime_string, modifiers)
Обрабатывает сигил для создания UTC даты и времени.
- sigil_W(term, modifiers)
Обрабатывает сигил для списков слов.
- sigil_w(term, modifiers)
Обрабатывает сигил для списков слов.
- spawn(fun)
Запускает заданную функцию и возвращает её PID.
- spawn(module, fun, args)
Запускает заданную функцию из заданного модуля, передавая ей заданные аргументы, и возвращает её PID.
- spawn_link(fun)
Запускает заданную функцию, связывая её с текущим процессом, и возвращает её PID.
- spawn_link(module, fun, args)
Запускает заданную функцию из заданного модуля, передавая ей заданные аргументы, связывая её с текущим процессом, и возвращает её PID.
- spawn_monitor(fun)
Запускает заданную функцию, отслеживает её и возвращает её PID и ссылку на мониторинг.
- spawn_monitor(module, fun, args)
Запускает заданный модуль и функцию, передавая заданные аргументы, отслеживает её и возвращает её PID и ссылку на мониторинг.
- struct(struct, fields \\ [])
Создаёт и обновляет структуру.
- struct!(struct, fields \\ [])
Аналогично
struct/2, но проверяет корректность ключей.- tap(value, fun)
Перенаправляет первый аргумент во второй аргумент, функцию, и возвращает первый аргумент само по себе.
- then(value, fun)
Перенаправляет первый аргумент во второй аргумент, функцию, и возвращает результат вызова функции.
- throw(term)
Нелокальный возврат из функции.
- to_charlist(term)
Преобразует заданный термин в список символов в соответствии с протоколом списка символов.
- to_string(term)
Преобразует аргумент в строку в соответствии с протоколом строк.
- unless(condition, clauses)
Предоставляет макрос для выполнения кода только если условие ложно.
- update_in(path, fun)
Обновляет вложенную структуру по заданному пути.
- update_in(data, keys, fun)
Обновляет ключ во вложенной структуре.
- use(module, opts \\ [])
Использует заданный модуль в текущем контексте.
- var!(var, context \\ nil)
Отмечает, что заданная переменная не должна быть гигиенизирована.
- left |> right
Оператор конвейера.
- left || right
Булевый оператор "или".
Операторы
left * rightSource
@spec integer() * integer() :: integer()
@spec float() * float() :: float()
@spec integer() * float() :: float()
@spec float() * integer() :: float()
Оператор умножения.
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> 1 * 2 2
+valueSource
@spec +integer() :: integer()
@spec +float() :: float()
Унарный оператор положительного числа.
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> +1 1
left + rightSource
@spec integer() + integer() :: integer()
@spec float() + float() :: float()
@spec integer() + float() :: float()
@spec float() + integer() :: float()
Оператор сложения.
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> 1 + 2 3
-valueSource
@spec -0 :: 0
@spec -pos_integer() :: neg_integer()
@spec -neg_integer() :: pos_integer()
@spec -float() :: float()
Унарный оператор отрицательного числа.
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> -2 -2
left - rightSource
@spec integer() - integer() :: integer()
@spec float() - float() :: float()
@spec integer() - float() :: float()
@spec float() - integer() :: float()
Оператор вычитания.
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> 1 - 2 -1
left / rightSource
@spec 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 != rightSource
@spec term() != term() :: boolean()
Оператор неравенства.
Возвращает true, если два значения не равны.
Этот оператор считает 1 и 1.0 равными. Для сравнения в соответствии с шаблоном используйте !==/2.
Все значения в Elixir могут быть сравнены друг с другом.
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> 1 != 2 true iex> 1 != 1.0 false
left !== rightSource
@spec term() !== term() :: boolean()
Оператор строгого неравенства.
Возвращает true, если два значения не строго равны. См. ===/2 для определения того, что считается "строго равным".
Все значения в Elixir могут быть сравнены друг с другом.
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> 1 !== 2 true iex> 1 !== 1.0 true
left < rightSource
@spec term() < term() :: boolean()
Оператор меньше.
Возвращает true, если left меньше right.
Выполняется структурное сравнение, где все значения Elixir могут быть сравнены друг с другом. Дополнительную информацию см. в разделе "Структурное сравнение".
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> 1 < 2 true
left <= rightSource
@spec term() <= term() :: boolean()
Оператор меньше или равно.
Возвращает true, если left меньше или равно right.
Выполняется структурное сравнение, где все значения Elixir могут быть сравнены друг с другом. Дополнительную информацию см. в разделе "Структурное сравнение".
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> 1 <= 2 true
left == rightSource
@spec term() == term() :: boolean()
Оператор равенства. Возвращает true, если два значения равны.
Этот оператор считает 1 и 1.0 равными. Для более строгого сравнения используйте ===/2.
Все значения в Elixir могут быть сравнены друг с другом.
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> 1 == 2 false iex> 1 == 1.0 true
left === rightSource
@spec term() === term() :: boolean()
Оператор строгого равенства.
Возвращает true, если два значения строго равны.
Значения считаются строго равными только если они имеют одинаковое значение и тип. Например, 1 == 1.0 возвращает true, но так как они имеют разные типы, 1 === 1.0 возвращает false.
Все значения в Elixir могут быть сравнены друг с другом.
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> 1 === 2 false iex> 1 === 1.0 false
left > rightSource
@spec term() > term() :: boolean()
Оператор больше.
Возвращает true, если left больше right.
Выполняется структурное сравнение, где все значения Elixir могут быть сравнены друг с другом. Дополнительную информацию см. в разделе "Структурное сравнение".
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> 1 > 2 false
left >= rightSource
@spec term() >= term() :: boolean()
Оператор больше или равно.
Возвращает true, если left больше или равно right.
Выполняется структурное сравнение, где все значения Elixir могут быть сравнены друг с другом. Дополнительную информацию см. в разделе "Структурное сравнение".
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> 1 >= 2 false
abs(number)Source
@spec abs(number()) :: number()
Возвращает целое или число с плавающей точкой, которое является абсолютным значением number.
Разрешен в проверках условий. Встроен компилятором.
Примеры
iex> abs(-3.33) 3.33 iex> abs(-3) 3
left and rightSource
Оператор логического "и".
Если left равно true, возвращает right; в противном случае возвращает false.
Требуется, чтобы только операнд right был булевым, так как оператор выполняется по принципу короткого замыкания. Если операнд left не является булевым, возникает исключение BadBooleanError.
Разрешен в проверках условий.
Примеры
iex> true and false false iex> true and "yay!" "yay!" iex> "yay!" and true ** (BadBooleanError) expected a boolean on left-side of "and", got: "yay!"
binary_part(binary, start, length)Source
@spec binary_part(binary(), non_neg_integer(), integer()) :: binary()
Извлекает часть двоичной строки, начиная с позиции start длиной length. Двоичные строки индексируются с нуля.
Если позиция start или длина length ссылаются на область за пределами двоичной строки, генерируется исключение ArgumentError.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> binary_part("foo", 1, 2)
"oo"
Отрицательная позиция может использоваться для извлечения байтов, которые находятся перед байтом по индексу start:
iex> binary_part("Hello", 5, -3)
"llo"
Исключение ArgumentError генерируется, когда длина выходит за пределы двоичной строки:
binary_part("Hello", 0, 10)
** (ArgumentError) argument error bit_size(bitstring)Source
@spec bit_size(bitstring()) :: non_neg_integer()
Возвращает целое число, которое представляет размер битовой строки в битах.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> bit_size(<<433::16, 3::3>>) 19 iex> bit_size(<<1, 2, 3>>) 24
byte_size(bitstring)Source
@spec byte_size(bitstring()) :: non_neg_integer()
Возвращает количество байтов, необходимых для хранения битовой строки.
То есть, если количество битов в битовой строке не делится на 8, результат будет округлён вверх (до ближайшего большего целого). Эта операция выполняется за постоянное время.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> byte_size(<<433::16, 3::3>>) 3 iex> byte_size(<<1, 2, 3>>) 3
ceil(number)Source
@spec ceil(number()) :: integer()
Возвращает наименьшее целое число, большее или равное заданному числу.
Если нужно выполнить операцию округления вверх для других десятичных знаков, используйте Float.ceil/2.
Разрешено в проверках условий. Встраивается компилятором.
div(dividend, divisor)Source
@spec div(integer(), neg_integer() | pos_integer()) :: integer()
Выполняет целочисленное деление.
Генерирует исключение ArithmeticError, если один из аргументов не является целым числом или когда делитель равен нулю.
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)Source
@spec elem(tuple(), non_neg_integer()) :: term()
Возвращает элемент по указанному индексу в кортеже.
Генерирует ArgumentError, если индекс отрицательный или выходит за пределы элементов кортежа.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
tuple = {:foo, :bar, 3}
elem(tuple, 1)
#=> :bar
elem({}, 0)
** (ArgumentError) argument error
elem({:foo, :bar}, 2)
** (ArgumentError) argument error floor(number)Source
@spec floor(number()) :: integer()
Возвращает наибольшее целое число, меньшее или равное заданному числу.
Если нужно выполнить операцию округления вниз для других десятичных знаков, используйте Float.floor/2.
Разрешено в проверках условий. Встраивается компилятором.
hd(list)Source
@spec hd(nonempty_maybe_improper_list(elem, any())) :: elem when elem: term()
Возвращает голову списка. Генерирует ArgumentError, если список пустой.
Голова списка — это его первый элемент.
Работает со списками, которые не являются собственными списками (improper lists).
Разрешено в проверках условий. Встраивается компилятором.
Примеры
hd([1, 2, 3, 4]) #=> 1 hd([1 | 2]) #=> 1
Для пустого списка генерируется исключение:
hd([]) #=> ** (ArgumentError) argument error
left in rightSource
Оператор принадлежности.
Проверяет, является ли элемент слева членом коллекции справа.
Примеры
iex> x = 1 iex> x in [1, 2, 3] true
Этот оператор (который является макросом) просто преобразуется в вызов Enum.member?/2. Приведённый выше пример преобразуется в:
Enum.member?([1, 2, 3], x)
Elixir также поддерживает left not in right, что эквивалентно not(left in right):
iex> x = 1 iex> x not in [1, 2, 3] false
Условия
Оператор in/2 (а также not in) может использоваться в условиях, если правая часть — это диапазон или список.
Если правая часть — список, Elixir преобразует оператор в выражение условия, которое должно проверить каждый элемент списка. Например:
when x in [1, 2, 3]
преобразуется в:
when x === 1 or x === 2 or x === 3
Однако, такая конструкция будет неэффективной для больших списков. В таких случаях лучше отказаться от условий и использовать более подходящую структуру данных, например, MapSet.
Если правая часть — диапазон, будет выполнена более эффективная проверка. Например:
when x in 1..1000
приблизительно преобразуется в:
when x >= 1 and x <= 1000
Учёт AST
left not in right анализируется компилятором в AST:
{:not, _, [{:in, _, [left, right]}]}
Это тот же AST, что и not(left in right).
Кроме того, Macro.to_string/2 и Code.format_string!/2 преобразуют все вхождения этого AST в left not in right.
is_atom(term)Source
@spec is_atom(term()) :: boolean()
Возвращает `true`, если `term` является атомом; иначе возвращает `false`.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> is_atom(false)
true
iex> is_atom(:name)
true
iex> is_atom(AnAtom)
true
iex> is_atom("true")
false is_binary(term)Source
@spec is_binary(term()) :: boolean()
Возвращает `true`, если `term` является двоичной строкой; иначе возвращает `false`.
Двоичная строка всегда содержит полное количество байтов.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> is_binary("foo")
true
iex> is_binary(<<1::3>>)
false is_bitstring(term)Source
@spec is_bitstring(term()) :: boolean()
Возвращает `true`, если `term` является битовой строкой (включая двоичную строку); иначе возвращает `false`.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> is_bitstring("foo")
true
iex> is_bitstring(<<1::3>>)
true is_boolean(term)Source
@spec is_boolean(term()) :: boolean()
Возвращает `true`, если `term` является либо атомом `true`, либо атомом `false` (то есть, булевым значением); иначе возвращает `false`.
Разрешено в проверках условий. Встраивается компилятором.
Примеры
iex> is_boolean(false) true iex> is_boolean(true) true iex> is_boolean(:test) false
is_exception(term)Source
Возвращает `true`, если `term` является исключением; иначе возвращает `false`.
Разрешено в проверках условий.
Примеры
iex> is_exception(%RuntimeError{})
true
iex> is_exception(%{})
false is_exception(term, name)Source
Возвращает true, если term является исключением типа name; иначе возвращает false.
Разрешено в проверках условий.
Примеры
iex> is_exception(%RuntimeError{}, RuntimeError)
true
iex> is_exception(%RuntimeError{}, Macro.Env)
false is_float(term)Source
@spec is_float(term()) :: boolean()
Возвращает true, если term является числом с плавающей точкой; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_function(term)Source
@spec is_function(term()) :: boolean()
Возвращает true, если term является функцией; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
Примеры
iex> is_function(fn x -> x + x end)
true
iex> is_function("not a function")
false is_function(term, arity)Source
@spec is_function(term(), non_neg_integer()) :: boolean()
Возвращает true, если term является функцией, которая может быть применена с arity количеством аргументов; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
Примеры
iex> is_function(fn x -> x * 2 end, 1) true iex> is_function(fn x -> x * 2 end, 2) false
is_integer(term)Source
@spec is_integer(term()) :: boolean()
Возвращает true, если term является целым числом; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_list(term)Source
@spec is_list(term()) :: boolean()
Возвращает true, если term является списком с нулём или более элементами; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_map(term)Source
@spec is_map(term()) :: boolean()
Возвращает true, если term является картой; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_map_key(map, key)Source
@spec is_map_key(map(), term()) :: boolean()
Возвращает true, если key является ключом в map; в противном случае возвращает false.
Вызывает BadMapError, если первый элемент не является картой.
Разрешено в тестах стражей. Встраивается компилятором.
is_nil(term)Source
Возвращает true, если term является nil, false в противном случае.
Разрешено в выражениях стражей.
Примеры
iex> is_nil(1) false iex> is_nil(nil) true
is_number(term)Source
@spec is_number(term()) :: boolean()
Возвращает true, если term является либо целым числом, либо числом с плавающей точкой; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_pid(term)Source
@spec is_pid(term()) :: boolean()
Возвращает true, если term является PID (идентификатор процесса); в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_port(term)Source
@spec is_port(term()) :: boolean()
Возвращает true, если term является идентификатором порта; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_reference(term)Source
@spec is_reference(term()) :: boolean()
Возвращает true, если term является ссылкой; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
is_struct(term)Source
Возвращает true, если term является структурой; в противном случае возвращает false.
Разрешено в тестах стражей.
Примеры
iex> is_struct(URI.parse("/"))
true
iex> is_struct(%{})
false is_struct(term, name)Source
Возвращает true, если term является структурой name; в противном случае возвращает false.
Разрешено в тестах стражей.
Примеры
iex> is_struct(URI.parse("/"), URI)
true
iex> is_struct(URI.parse("/"), Macro.Env)
false is_tuple(term)Source
@spec is_tuple(term()) :: boolean()
Возвращает true, если term является кортежем; в противном случае возвращает false.
Разрешено в тестах стражей. Встраивается компилятором.
length(list)Source
@spec length(list()) :: non_neg_integer()
Возвращает длину list.
Разрешено в тестах стражей. Встраивается компилятором.
Примеры
iex> length([1, 2, 3, 4, 5, 6, 7, 8, 9]) 9
map_size(map)Source
@spec map_size(map()) :: non_neg_integer()
Возвращает размер карты.
Размер карты — это количество пар ключ-значение, которые содержит карта.
Эта операция выполняется за константное время.
Разрешено в тестах стражей. Встраивается компилятором.
Примеры
iex> map_size(%{a: "foo", b: "bar"})
2 node()Source
@spec node() :: node()
Возвращает атом, представляющий имя локального узла. Если узел не активен, вместо этого возвращается :erlang.node().
Разрешено в тестах стражей. Встраивается компилятором.
node(arg)Source
@spec node(pid() | reference() | port()) :: node()
Возвращает узел, где находится данный аргумент. Аргументом может быть PID, ссылка или порт. Если локальный узел не активен, возвращается :erlang.node().
Разрешено в тестах стражей. Встраивается компилятором.
not valueSource
@spec not true :: false
@spec not false :: true
Оператор строгой логической инверсии.
value должен быть булевым; если это не так, генерируется исключение ArgumentError.
Разрешено в тестах стражей. Встраивается компилятором.
Примеры
iex> not false true
left or rightSource
Оператор строгой логической дизъюнкции.
Если left является true, возвращает true; в противном случае возвращает right.
Требуется, чтобы только left операнд был булевым, поскольку он выполняется по принципу короткого замыкания. Если left операнд не является булевым, генерируется исключение BadBooleanError.
Разрешено в тестах стражей.
Примеры
iex> true or false true iex> false or 42 42 iex> 42 or false ** (BadBooleanError) expected a boolean on left-side of "or", got: 42
rem(делимое, делитель)Source
@spec rem(integer(), neg_integer() | pos_integer()) :: integer()
Вычисляет остаток от деления целых чисел.
rem/2 использует усечение при делении, что означает, что результат всегда будет иметь знак dividend.
Вызывает исключение ArithmeticError, если один из аргументов не является целым числом или когда divisor является 0.
Разрешено в тестах условий. Встроен компилятором.
Примеры
iex> rem(5, 2) 1 iex> rem(6, -4) 2
round(число)Source
@spec round(number()) :: integer()
Округляет число до ближайшего целого.
Если число равноудалено от двух ближайших целых чисел, округляет от нуля.
Разрешено в тестах условий. Встроен компилятором.
Примеры
iex> round(5.6) 6 iex> round(5.2) 5 iex> round(-9.9) -10 iex> round(-9) -9 iex> round(2.5) 3 iex> round(-2.5) -3
self()Source
@spec self() :: pid()
Возвращает PID (идентификатор процесса) вызывающего процесса.
Разрешено в условиях. Встроен компилятором.
tl(список)Source
@spec tl(nonempty_maybe_improper_list(elem, last)) :: maybe_improper_list(elem, last) | last when elem: term(), last: term()
Возвращает хвост списка. Вызывает ArgumentError, если список пуст.
Хвостом списка является список без его первого элемента.
Работает со списками неправильной структуры.
Разрешено в тестах условий. Встроен компилятором.
Примеры
tl([1, 2, 3, :go])
#=> [2, 3, :go]
tl([:one])
#=> []
tl([:a, :b | :improper_end])
#=> [:b | :improper_end]
tl([:a | %{b: 1}])
#=> %{b: 1}
Передача пустого списка вызывает:
tl([]) #=> ** (ArgumentError) argument error
trunc(число)Source
@spec trunc(number()) :: integer()
Возвращает целую часть number.
Разрешено в тестах условий. Встроен компилятором.
Примеры
iex> trunc(5.4) 5 iex> trunc(-5.99) -5 iex> trunc(-5) -5
tuple_size(кортеж)Source
@spec tuple_size(tuple()) :: non_neg_integer()
Возвращает размер кортежа.
Эта операция выполняется за постоянное время.
Разрешено в тестах условий. Встроен компилятором.
Примеры
iex> tuple_size({:a, :b, :c})
3 Функции
left && rightSource
Логический оператор "и".
Обеспечивает оператор короткого замыкания, который оценивает и возвращает второе выражение только в том случае, если первое выражение оценивается как истинное значение (ни 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, этот оператор принимает любое выражение в качестве первого аргумента, а не только булевы значения.
base ** exponentSource
@spec integer() ** non_neg_integer() :: integer()
@spec integer() ** neg_integer() :: float()
@spec float() ** float() :: float()
Оператор возведения в степень.
Ожидает два числовых входных значения. Если левая часть — целое число, а правая — неотрицательное число, результат — целое число. В противном случае возвращается число с плавающей точкой.
Примеры
iex> 2 ** 2 4 iex> 2 ** -4 0.0625 iex> 2.0 ** 2 4.0 iex> 2 ** 2.0 4.0
left ++ rightSource
@spec list() ++ term() :: maybe_improper_list()
Оператор конкатенации списков. Объединяет правильный список и элемент, возвращая список.
Сложность a ++ b пропорциональна length(a), поэтому избегайте многократного добавления в списки произвольной длины, например, list ++ [element]. Вместо этого рассмотрите возможность добавления в начало посредством [element | rest] и последующего реверсирования.
Если операнд right не является правильным списком, возвращается неправильный список. Если операнд left не является правильным списком, генерируется исключение ArgumentError.
Встраивается компилятором.
Примеры
iex> [1] ++ [2, 3] [1, 2, 3] iex> 'foo' ++ 'bar' 'foobar' # returns an improper list iex> [1] ++ 2 [1 | 2] # returns a proper list iex> [1] ++ [2] [1, 2] # improper list on the right will return an improper list iex> [1] ++ [2 | 3] [1, 2 | 3]
left -- rightSource
@spec list() -- list() :: list()
Оператор вычитания списков. Удаляет первое вхождение элемента из левого списка для каждого элемента справа.
Функция оптимизирована, поэтому сложность a -- b пропорциональна length(a) * log(length(b)). См. также руководство по эффективности Erlang.
Встраивается компилятором.
Примеры
iex> [1, 2, 3] -- [1, 2] [3] iex> [1, 2, 3, 2, 1] -- [1, 2, 2] [3, 1]
Оператор --/2 является правоассоциативным, что означает:
iex> [1, 2, 3] -- [2] -- [3] [1, 3]
Что эквивалентно:
iex> [1, 2, 3] -- ([2] -- [3]) [1, 3]
..Source
Создаёт полный диапазон слайсов 0..-1//1.
Этот макрос возвращает диапазон со следующими свойствами:
При перечислении он пуст
При использовании как
slice, возвращает срезанный элемент как есть
См. ..///3 и модуль Range для получения дополнительной информации.
Примеры
iex> Enum.to_list(..)
[]
iex> String.slice("Hello world!", ..)
"Hello world!" first..lastSource
Создаёт диапазон от first до last.
Если first меньше last, диапазон будет возрастать от first до last. Если first равно last, диапазон будет содержать один элемент — само число.
Если first больше last, диапазон будет убывать от first до last, хотя это поведение устарело. Вместо этого предпочтительнее явно указать шаг с first..last//-1.
См. модуль Range для получения дополнительной информации.
Примеры
iex> 0 in 1..3 false iex> 2 in 1..3 true iex> Enum.to_list(1..3) [1, 2, 3]
first..last//stepSource
Создаёт диапазон от first до last с step.
См. модуль Range для получения дополнительной информации.
Примеры
iex> 0 in 1..3//1 false iex> 2 in 1..3//1 true iex> 2 in 1..3//2 false iex> Enum.to_list(1..3//1) [1, 2, 3] iex> Enum.to_list(1..3//2) [1, 3] iex> Enum.to_list(3..1//-1) [3, 2, 1] iex> Enum.to_list(1..0//1) []
!valueSource
Логический оператор "не".
Принимает любое значение (не только булевы значения) и возвращает true , если value равно false или nil; в противном случае возвращает false.
Запрещено в условиях защиты.
Примеры
iex> !Enum.empty?([]) false iex> !List.first([]) true
left <> rightSource
Оператор бинарной конкатенации. Объединяет две бинарные строки.
Генерирует исключение ArgumentError, если один из операндов не является бинарной строкой.
Примеры
iex> "foo" <> "bar" "foobar"
Оператор <>/2 также может использоваться в шаблонах (и условиях защиты), если левый операнд — это литеральная бинарная строка:
iex> "foo" <> x = "foobar" iex> x "bar"
x <> "bar" = "foobar" приведет к исключению ArgumentError.
left =~ rightSource
@spec String.t() =~ (String.t() | Regex.t()) :: boolean()
Оператор сопоставления по тексту. Сопоставляет терм в left с регулярным выражением или строкой в right.
Если right — регулярное выражение, возвращает true если left соответствует right.
Если right — строка, возвращает true если left содержит right.
Примеры
iex> "abcd" =~ ~r/c(d)/ true iex> "abcd" =~ ~r/e/ false iex> "abcd" =~ ~r// true iex> "abcd" =~ "bc" true iex> "abcd" =~ "ad" false iex> "abcd" =~ "abcd" true iex> "abcd" =~ "" true
Для получения дополнительной информации о регулярных выражениях, пожалуйста, обратитесь к модулю Regex.
@exprSource
Унарный оператор атрибута модуля.
Читает и записывает атрибуты в текущем модуле.
Канонический пример атрибутов — это аннотация, что модуль реализует поведение 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.
Важно: Библиотеки и фреймворки должны учитывать префикс нижнего подчёркивания для любых атрибутов модулей, которые являются приватными, например,
@_my_data, чтобы инструменты автодополнения не показывали их в подсказках и предложениях.
И наконец, обратите внимание, что атрибуты также можно читать внутри функций:
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 для других функций управления атрибутами модулей.
Внимание! Несколько ссылок на один и тот же атрибут
Как упоминалось выше, каждый раз при чтении атрибута модуля создаётся снимок его текущего значения. Поэтому, если вы храните большие значения в атрибутах модулей (например, встраиваете внешние файлы в атрибуты модулей), следует избегать множественных ссылок на один и тот же атрибут. Например, не делайте так:
@files %{
example1: File.read!("lib/example1.data"),
example2: File.read!("lib/example2.data")
}
def example1, do: @files[:example1]
def example2, do: @files[:example2]
В приведенном выше примере каждая ссылка на @files может привести к полной и отдельной копии всего атрибута модуля @files. Вместо этого обратитесь к атрибуту модуля один раз в приватной функции:
@files %{
example1: File.read!("lib/example1.data"),
example2: File.read!("lib/example2.data")
}
defp files(), do: @files
def example1, do: files()[:example1]
def example2, do: files()[:example2]
Внимание! Зависимости от этапа компиляции
Помните, что ссылки на другие модули, даже в атрибутах модулей, создают зависимости от этапа компиляции к этим модулям.
Например, рассмотрите этот распространённый шаблон:
@values [:foo, :bar, :baz] def handle_arg(arg) when arg in @values do ... end
Хотя приведенный выше пример верен, представьте, что вместо этого у вас есть фактические имена модулей в атрибуте модуля, как в этом случае:
@values [Foo, Bar, Baz] def handle_arg(arg) when arg in @values do ... end
Код выше определит зависимость от этапа компиляции от модулей Foo, Bar, и Baz, таким образом, что при изменении любого из них текущему модулю придётся перекомпилироваться. В таких случаях может быть предпочтительнее вообще избегать атрибута модуля:
def handle_arg(arg) when arg in [Foo, Bar, Baz] do ... end
alias!(alias)Source
При использовании внутри цитирования помечает, что данный псевдоним не должен подвергаться гигиене. Это означает, что псевдоним будет расширен при расширении макроса.
См. Kernel.SpecialForms.quote/2 для получения дополнительной информации.
apply(fun, args)Source
@spec apply((... -> any()), [any()]) :: any()
Вызывает заданную анонимную функцию fun со списком аргументов args.
Если количество аргументов известно на этапе компиляции, предпочтительнее использовать fun.(arg_1, arg_2, ..., arg_n) — оно более понятно, чем apply(fun, [arg_1, arg_2, ..., arg_n]).
Встраивается компилятором.
Примеры
iex> apply(fn x -> x * 2 end, [2]) 4
apply(module, function_name, args)Source
@spec apply(module(), function_name :: atom(), [any()]) :: any()
Вызывает заданную функцию из module со списком аргументов args.
apply/3 используется для вызова функций, где модуль, имя функции или аргументы определяются динамически во время выполнения. По этой причине вы не можете вызывать макросы с помощью apply/3, только функции.
Если количество аргументов и имя функции известны на этапе компиляции, предпочтительнее использовать module.function(arg_1, arg_2, ..., arg_n) — оно более понятно, чем apply(module, :function, [arg_1, arg_2, ..., arg_n]).
apply/3 не может использоваться для вызова закрытых функций.
Встраивается компилятором.
Примеры
iex> apply(Enum, :reverse, [[1, 2, 3]]) [3, 2, 1]
binary_slice(binary, range)Source
Возвращает двоичную строку от смещения, заданного началом диапазона, до смещения, заданного концом диапазона.
Если начало или конец диапазона отрицательны, они преобразуются в положительные индексы на основе размера двоичной строки. Например, -1 означает последний байт двоичной строки.
Аналогично binary_part/3, но работает с диапазонами и не разрешено в охранных выражениях.
Функция работает с байтами. Для операции среза, учитывающей символы, см. String.slice/2.
Примеры
iex> binary_slice("elixir", 0..5)
"elixir"
iex> binary_slice("elixir", 1..3)
"lix"
iex> binary_slice("elixir", 1..10)
"lixir"
iex> binary_slice("elixir", -4..-1)
"ixir"
iex> binary_slice("elixir", -4..6)
"ixir"
iex> binary_slice("elixir", -10..10)
"elixir"
Для диапазонов, где start > stop, необходимо явно указать их как возрастающие:
iex> binary_slice("elixir", 2..-1//1)
"ixir"
iex> binary_slice("elixir", 1..-2//1)
"lixi"
Можно использовать ../0 как сокращение для 0..-1//1, которое возвращает всю двоичную строку как есть:
iex> binary_slice("elixir", ..)
"elixir"
Шаг может быть любым положительным числом. Например, чтобы получить каждый второй символ двоичной строки:
iex> binary_slice("elixir", 0..-1//2)
"eii"
Если первая позиция находится за пределами строки или после последней позиции диапазона, возвращается пустая строка:
iex> binary_slice("elixir", 10..3//1)
""
iex> binary_slice("elixir", -10..-7)
""
iex> binary_slice("a", 1..1500)
"" binary_slice(binary, start, size)Source
Возвращает двоичную строку, начинающуюся со смещения start и заданного size.
Аналогично binary_part/3, но если start + size больше размера двоичной строки, она автоматически обрезается до размера двоичной строки вместо повышения ошибки. В отличие от binary_part/3, эта функция не разрешена в охранных выражениях.
Функция работает с байтами. Для операции среза, учитывающей символы, см. String.slice/3.
Примеры
iex> binary_slice("elixir", 0, 6)
"elixir"
iex> binary_slice("elixir", 0, 5)
"elixi"
iex> binary_slice("elixir", 1, 4)
"lixi"
iex> binary_slice("elixir", 0, 10)
"elixir"
Если start отрицательное, оно нормализуется относительно размера двоичной строки и ограничено значением 0:
iex> binary_slice("elixir", -3, 10)
"xir"
iex> binary_slice("elixir", -10, 10)
"elixir"
Если size равно нулю, возвращается пустая двоичная строка:
iex> binary_slice("elixir", 1, 0)
""
Если start больше или равно размеру двоичной строки, возвращается пустая двоичная строка:
iex> binary_slice("elixir", 10, 10)
"" binding(context \\ nil)Source
Возвращает контекст связывания для данного контекста в виде списка ключевых слов.
В возвращенном результате ключи — имена переменных, а значения — соответствующие значения переменных.
Если указанный 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]
dbg(code \\ quote do binding() end, options \\ [])Source
Отлаживает заданный code.
dbg/2 может использоваться для отладки данного code через настраиваемую функцию отладки. Возвращает результат заданного кода.
Примеры
Рассмотрим этот вызов dbg/2:
dbg(Atom.to_string(:debugging)) #=> "debugging"
Возвращает строку "debugging", которая является результатом вызова Atom.to_string/1. Кроме того, приведенный выше вызов выводит:
[my_file.ex:10: MyMod.my_fun/0] Atom.to_string(:debugging) #=> "debugging"
По умолчанию, функция отладки выводит дополнительную отладочную информацию при работе с конвейерами. Она выводит значения на каждой "ступеньке" конвейера.
"Elixir is cool!"
|> String.trim_trailing("!")
|> String.split()
|> List.first()
|> dbg()
#=> "Elixir"
Приведенный выше код выводит:
[my_file.ex:10: MyMod.my_fun/0]
"Elixir is cool!" #=> "Elixir is cool!"
|> String.trim_trailing("!") #=> "Elixir is cool"
|> String.split() #=> ["Elixir", "is", "cool"]
|> List.first() #=> "Elixir"
Без аргументов, dbg() отлаживает информацию о текущем контексте связывания. См. binding/1.
Настройка функции отладки
Одним из преимуществ dbg/2 является возможность конфигурации логики отладки, что позволяет инструментам расширять dbg с улучшенным поведением. Это делается, например, IEx, которая расширяет dbg интерактивной оболочкой, где вы можете напрямую просматривать и получать доступ к значениям.
Функция отладки может быть настроена во время компиляции через ключ :dbg_callback приложения :elixir. Функция отладки должна быть кортежем {module, function, args}. Функция function в module будет вызвана с тремя аргументами, предваряющими args.
Функция отладки вызывается во время компиляции и также должна возвращать AST. AST ожидается, что, в конечном итоге, вернет результат оценки отлаживаемого выражения.
Вот простой пример:
defmodule MyMod do
def debug_fun(code, options, caller, device) do
quote do
result = unquote(code)
IO.inspect(unquote(device), result, label: unquote(Macro.to_string(code)))
end
end
end
Для настройки функции отладки:
# In config/config.exs
config :elixir, :dbg_callback, {MyMod, :debug_fun, [:stdio]}
Функция отладки по умолчанию
По умолчанию, функция отладки — Macro.dbg/3. Она просто выводит информацию о коде в стандартный вывод и возвращает значение, возвращаемое при оценке code. options используются для управления тем, как просматриваются термины. Они совпадают с параметрами, принимаемыми функцией inspect/2.
def(call, expr \\ nil)Source
Определяет общедоступную функцию с заданным именем и телом.
Примеры
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
Обратите внимание, что \\ нельзя использовать с анонимными функциями, поскольку у них может быть только одна арность.
Списки ключевых слов с аргументами по умолчанию
Функции, содержащие множество аргументов, могут извлечь выгоду из использования списков ключевых слов для группировки и передачи атрибутов как одного значения.
defmodule MyConfiguration do
@default_opts [storage: "local"]
def configure(resource, opts \\ []) do
opts = Keyword.merge(@default_opts, opts)
storage = opts[:storage]
# ...
end
end
Разница между использованием Map и Keyword для хранения многих аргументов заключается в ключах Keyword:
- должны быть атомами
- могут быть заданы несколько раз
- упорядочены, как указано разработчиком
Имена функций и переменных
Имена функций и переменных имеют следующий синтаксис: нижняя регистровая 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 (известно как "явное try"). Например, следующие две функции эквивалентны:
def convert(number) do
try do
String.to_integer(number)
rescue
e in ArgumentError -> {:error, e.message}
end
end
def convert(number) do
String.to_integer(number)
rescue
e in ArgumentError -> {:error, e.message}
end defdelegate(funs, opts)Source
Определяет функцию, которая делегирует вызов другой модуль.
Функции, определенные с помощью 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)Source
Определяет исключение.
Исключения представляют собой структуры, поддерживаемые модулем, реализующим поведение Exception. Поведение Exception требует реализации двух функций:
exception/1- принимает аргументы, переданные вraise/2, и возвращает структуру исключения. Реализация по умолчанию принимает либо набор ключевых аргументов, которые объединяются в структуру, либо строку, которая используется в качестве сообщения об исключении.message/1- принимает структуру исключения и должна вернуть её сообщение. Чаще всего у исключений есть поле message, которое по умолчанию используется этой функцией. Однако, если исключение не имеет поля message, эта функция должна быть явно реализована.
Поскольку исключения являются структурами, API, поддерживаемый defstruct/1, также доступен в defexception/1.
Выбрасывание исключений
Наиболее распространенный способ выброса исключения - через raise/2:
defmodule MyAppError do
defexception [:message]
end
value = [:hello]
raise MyAppError,
message: "did not get what was expected, got: #{inspect(value)}"
Во многих случаях удобнее передать ожидаемое значение в raise/2 и сгенерировать сообщение в обработчике Exception.exception/1:
defmodule MyAppError do
defexception [:message]
@impl true
def exception(value) do
msg = "did not get what was expected, got: #{inspect(value)}"
%MyAppError{message: msg}
end
end
raise MyAppError, value
Приведенный выше пример демонстрирует предпочтительную стратегию настройки сообщений об исключениях.
defguard(guard)Source
@spec 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)Source
@spec defguardp(Macro.t()) :: Macro.t()
Генерирует частный макрос, подходящий для использования в выражениях-стражах.
Вызывает ошибку во время компиляции, если определение использует выражения, запрещенные в стражах, и в противном случае создает частный макрос, который может быть использован как внутри, так и вне стражей в текущем модуле.
Аналогично defmacrop/2, defguardp/1 должен быть определен до его использования в текущем модуле.
defimpl(name, opts, do_block \\ [])Source
Определяет реализацию для данного протокола.
См. модуль Protocol для получения дополнительной информации.
defmacro(call, expr \\ nil)Source
Определяет публичный макрос с заданным именем и телом.
Макросы должны быть определены до их использования.
См. 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)Source
Определяет закрытый макрос с заданным именем и телом.
Закрытые макросы доступны только из того же модуля, в котором они определены.
Закрытые макросы должны быть определены до их использования.
См. defmacro/2 для получения дополнительной информации, и см. def/2 для правил именования и аргументов по умолчанию.
defmodule(alias, do_block)Source
Определяет модуль с заданным именем и содержимым.
Этот макрос определяет модуль с заданным alias в качестве имени и заданным содержимым. Он возвращает кортеж из четырёх элементов:
:module- имя модуля
- бинарное содержимое модуля
- результат выполнения блока содержимого
Примеры
defmodule Number do
def one, do: 1
def two, do: 2
end
#=> {:module, Number, <<70, 79, 82, ...>>, {:two, 0}}
Number.one()
#=> 1
Number.two()
#=> 2
Вложенность
Вложенность модуля внутри другого модуля влияет на имя вложенного модуля:
defmodule Foo do defmodule Bar do end end
В примере выше создаются два модуля — Foo и Foo.Bar. При вложенности Elixir автоматически создаёт псевдоним для внутреннего модуля, позволяя обращаться ко второму модулю Foo.Bar как к Bar в том же лексическом пространстве, где он определён (в модуле Foo). Это происходит только если вложенный модуль определён через псевдоним.
Если модуль Foo.Bar перемещен в другое место, ссылки на Bar в модуле Foo необходимо обновить на полное имя (Foo.Bar) или установить псевдоним в модуле Foo с помощью Kernel.SpecialForms.alias/2.
defmodule Foo.Bar do # code end defmodule Foo do alias Foo.Bar # code here can refer to "Foo.Bar" as just "Bar" end
Динамические имена
Имена модулей в Elixir могут быть динамически сгенерированы. Это очень полезно при работе с макросами. Например, можно написать:
defmodule String.to_atom("Foo#{1}") do
# contents ...
end
Elixir примет любое имя модуля, если выражение, переданное в качестве первого аргумента в defmodule/2, вычисляется до атома. Обратите внимание, что при использовании динамического имени Elixir не будет вкладывать имя в текущий модуль и не будет автоматически устанавливать псевдоним.
Зарезервированные имена модулей
Если вы попытаетесь определить модуль, который уже существует, вы получите предупреждение о том, что модуль был переопределен.
Существуют некоторые модули, которые Elixir пока не реализует, но может реализовать в будущем. Эти модули зарезервированы, и их определение приведёт к ошибке компиляции:
defmodule Any do # code end ** (CompileError) iex:1: module Any is reserved and cannot be defined
Elixir зарезервировал следующие имена модулей: Elixir, Any, BitString, PID, и Reference.
defoverridable(keywords_or_behaviour)Source
Делает заданные определения в текущем модуле переопределяемыми.
Если пользователь определит новую функцию или макрос с тем же именем и арностью, то переопределяемые определения будут отброшены. В противном случае будут использованы исходные определения.
Возможна ситуация, когда переопределённое определение имеет другую видимость, чем оригинальное: публичная функция может быть переопределена приватной функцией и наоборот.
Макросы не могут быть переопределены как функции, и наоборот.
Пример
defmodule DefaultMod do
defmacro __using__(_opts) do
quote do
def test(x, y) do
x + y
end
defoverridable test: 2
end
end
end
defmodule ChildMod do
use DefaultMod
def test(x, y) do
x * y + super(x, y)
end
end
Как видно из примера выше, super можно использовать для вызова реализации по умолчанию.
Примечание: используйте
defoverridableс осторожностью. Если вам нужно определить несколько модулей с одинаковым поведением, лучше перенести реализацию по умолчанию в вызывающий модуль и проверить наличие обратного вызова с помощьюCode.ensure_loaded?/1иfunction_exported?/3.Например, в примере выше, представьте, что есть модуль, который вызывает функцию
test/2. Этот модуль может быть определён следующим образом:defmodule CallsTest do def receives_module_and_calls_test(module, x, y) do if Code.ensure_loaded?(module) and function_exported?(module, :test, 2) do module.test(x, y) else x + y end end end
Пример с поведением
Вы также можете передать поведение в defoverridable, и оно отметит все обратные вызовы в поведении как переопределяемые:
defmodule Behaviour do
@callback test(number(), number()) :: number()
end
defmodule DefaultMod do
defmacro __using__(_opts) do
quote do
@behaviour Behaviour
def test(x, y) do
x + y
end
defoverridable Behaviour
end
end
end
defmodule ChildMod do
use DefaultMod
def test(x, y) do
x * y + super(x, y)
end
end defp(call, expr \\ nil)Source
Определяет приватную функцию с заданным именем и телом.
Приватные функции доступны только внутри модуля, в котором они определены. Попытка доступа к приватной функции извне модуля, в котором она определена, приводит к исключению 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)Source
Определяет протокол.
См. модуль Protocol для получения дополнительной информации.
defstruct(fields)Source
Определяет структуру.
Структура — это помеченная карта, которая позволяет разработчикам предоставлять значения по умолчанию для ключей, метки для использования в полиморфных диспетчерах и проверки типов на этапе компиляции. Для получения дополнительной информации о структурах, обратитесь к Kernel.SpecialForms.%/2.
Определение структуры возможно только в рамках одного модуля, поскольку структура привязана к самому модулю. Вызов defstruct/1 также определяет функцию __struct__/0, которая возвращает саму структуру.
Примеры
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: nil end MyProtocol.call(john) # it works!
Частый пример — наследовать протокол Inspect для скрытия определённых полей при печати структуры:
defmodule User do
@derive {Inspect, only: :name}
defstruct name: nil, age: nil
end
Для каждого протокола в @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)Source
Деструктурирует два списка, присваивая каждый элемент в правом списке соответствующему элементу в левом.
В отличие от паттерн-сопоставления с помощью =, если размеры левого и правого списков не совпадают, деструктурирование просто останавливается, а не генерирует ошибку.
Примеры
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)Source
@spec 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) при завершении процесса тестирования, чтобы сообщить связанным процессам, деревьям надзора и т.д. о вежливом завершении работы.
Выходы командной строки
На основании сигналов завершения, упомянутых выше, если процесс, запущенный из командной строки, завершается с любой из трёх причин выше, его выход считается нормальным, и процесс операционной системы завершается со статусом 0.
Однако, можно настроить сигнал завершения операционной системы, вызвав:
exit({:shutdown, integer})
Это заставит процесс операционной системы завершиться со статусом, заданным integer, одновременно сигнализируя всем связанным процессам Erlang о вежливом завершении работы.
Любая другая причина выхода приведёт к завершению процесса операционной системы со статусом 1 и краху связанных процессов Erlang.
function_exported?(module, function, arity)Source
@spec function_exported?(module(), atom(), arity()) :: boolean()
Возвращает true, если модуль загружен и содержит общедоступную функцию с заданным именем и арностью, в противном случае 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)Source
Получает значение и обновляет вложенную структуру данных с помощью заданной функции.
Аналогично 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})
Это также работает со вложенными структурами и способом указания путей с помощью макроса:
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}}}
Пути
Путь может начинаться с переменной, локального или удалённого вызова и должен быть продолжен одним или несколькими:
&{var}- обращается к ключу в переменной; в случае, если переменная имеет значение nil, возвращается nil&{key}- обращается к полю карты/структуры; в случае отсутствия поля генерируется ошибка
Вот некоторые допустимые пути:
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)Source
@spec get_and_update_in(
structure,
keys,
(term() | nil -> {current_value, new_value} | :pop)
) :: {current_value, new_structure :: structure}
when structure: Access.t(),
keys: [any(), ...],
current_value: Access.value(),
new_value: Access.value() Получает значение и обновляет вложенную структуру.
data — это вложенная структура (то есть карта, список ключевых слов или структура, реализующая поведение Access).
Аргумент fun получает значение (или nil, если значение отсутствует) и должен вернуть одно из следующих значений:
двухэлементная кортеж
{old_value, new_value}. В этом случаеold_value— это полученное значение, которое можно, возможно, обработать перед возвратом.new_value— новое значение, которое должно быть сохранено под указанным ключом.nil, что подразумевает удаление текущего значения из структуры и возврат этого значения.
Эта функция использует модуль Access для обхода структур в соответствии с заданными ключами, если fun не является функцией, что подробно описано в последующем разделе.
Примеры
Эта функция полезна, когда необходимо получить текущее значение (или значение, вычисленное в зависимости от текущего значения) и обновить его одновременно. Например, её можно использовать для чтения текущего возраста пользователя и увеличения его на единицу за один проход:
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}}}
Обратите внимание, что текущее значение, переданное анонимной функции, может быть nil. Если любое из промежуточных значений равно nil, произойдёт исключение:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users, ["jane", :age], &{&1, &1 + 1})
** (ArgumentError) could not put/update key :age on a nil value
Функции в качестве ключей
Если ключ является функцией, функция будет вызвана с тремя аргументами:
- операция (
get_and_update_in/3) - данные для доступа
- функция, которая будет вызвана далее
Это означает, что 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 поставляется с множеством удобных функций доступа, таких как анонимная функция fn x -> {x, x + 1} end выше. См. Access.all/0, Access.key/2 и другие примеры.
get_in(data, keys)Source
@spec get_in(Access.t(), [term(), ...]) :: term()
Получает значение из вложенной структуры.
Использует модуль Access для обхода структур в соответствии с заданными ключами, если fun не является функцией, что подробно описано в последующем разделе.
Обратите внимание, что если ни один из заданных ключей не является функцией, редко есть причина использовать get_in вместо написания «обычного» кода Elixir с использованием сопоставления с образцом.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users, ["john", :age])
27
iex> # Equivalent to:
iex> users["john"][:age]
27
get_in/2 также может использовать аксессоры в модуле Access для обхода более сложных структур данных. Например, здесь мы используем Access.all/0 для обхода списка:
iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> get_in(users, [Access.all(), :age])
[27, 23]
В случае если любой из компонентов возвращает nil, будет возвращено nil, и get_in/2 не будет продолжать обход:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users, ["unknown", :age])
nil
iex> # Equivalent to:
iex> users["unknown"][:age]
nil
iex> users = nil
iex> get_in(users, [Access.all(), :age])
nil
В качестве альтернативы, если вам нужно получить доступ к сложным структурам данных, вы можете использовать сопоставление с образцом:
case users do
%{"john" => %{age: age}} -> age
_ -> default_value
end
Функции в качестве ключей
Если ключ, переданный get_in/2, является функцией, функция будет вызвана с тремя аргументами:
- операция (
get_in/2) - данные для доступа
- функция, которая будет вызвана далее
Это означает, что get_in/2 можно расширить для предоставления настраиваемых поисков. Именно так работает ключ Access.all/0 в предыдущем разделе. Например, мы можем вручную реализовать такой обход следующим образом:
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]
Модуль Access поставляется с множеством удобных функций доступа. См. Access.all/0, Access.key/2 и другие примеры.
Работа со структурами
По умолчанию структуры не реализуют поведение Access, необходимое этой функции. Поэтому вы не можете сделать это:
get_in(some_struct, [:some_key, :nested_key])
Хорошая новость заключается в том, что структуры имеют предопределённую форму. Поэтому вы можете написать вместо этого:
some_struct.some_key.nested_key
Если get_in/2 может вернуть nil, вы всегда можете использовать сопоставление с образцом для обработки вложенных структур:
case some_struct do
%{some_key: %{nested_key: value}} -> value
%{} -> nil
end if(condition, clauses)Source
Обеспечивает макрос if/2.
Этот макрос ожидает, что первый аргумент будет условием, а второй — списком ключевых слов.
Примеры однострочных выражений
if(foo, do: bar)
В примере выше, value будет возвращено, если condition вычислится как истинное значение (ни false ни nil). В противном случае, будет возвращено else_value.
Можно указать опцию else, чтобы указать обратное:
if(foo, do: bar, else: baz)
Примеры с блоками
Также можно передать блок макросу if/2. Первый пример выше будет преобразован в:
if foo do bar end
Обратите внимание, что condition и else_value становятся разделителями. Второй пример будет преобразован в:
if foo do bar else baz end
Для сравнения более чем двух условий необходимо использовать макрос cond/1.
inspect(term, opts \\ [])Source
@spec 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)Source
@spec 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()Source
@spec make_ref() :: reference()
Возвращает почти уникальную ссылку.
Возвращаемая ссылка появится снова примерно через 2^82 вызовов; следовательно, она достаточно уникальна для практических целей.
Встраивается компилятором.
Примеры
make_ref() #=> #Reference<0.0.0.135>
match?(pattern, expr)Source
Удобный макрос, проверяющий, совпадает ли правая часть (выражение) с левой частью (шаблоном).
Примеры
iex> match?(1, 1)
true
iex> match?({1, _}, {1, 2})
true
iex> map = %{a: 1, b: 2}
iex> match?(%{a: _}, map)
true
iex> a = 1
iex> match?(^a, 1)
true
match?/2 очень полезен при фильтрации или поиске значения в перечисляемом:
iex> list = [a: 1, b: 2, a: 3]
iex> Enum.filter(list, &match?({:a, _}, &1))
[a: 1, a: 3]
К условиям сопоставления также можно добавлять условия:
iex> list = [a: 1, b: 2, a: 3]
iex> Enum.filter(list, &match?({:a, x} when x < 2, &1))
[a: 1]
Переменные, назначенные в сопоставлении, будут недоступны за пределами вызова функции (в отличие от обычного сопоставления шаблонов с оператором =):
iex> match?(_x, 1) true iex> binding() []
Значения против шаблонов
Помните, что оператор привязки соответствует значениям, а не шаблонам. Передача переменной в качестве шаблона всегда вернёт true и вызовет предупреждение о том, что переменная не используется:
# don't do this
pattern = %{a: :a}
match?(pattern, %{b: :b})
Аналогично, перемещение выражения из шаблона может больше не сохранять его семантику. Например:
match?([_ | _], [1, 2, 3]) #=> true pattern = [_ | _] match?(pattern, [1, 2, 3]) ** (CompileError) invalid use of _. "_" represents a value to be ignored in a pattern and cannot be used in expressions
Ещё один пример: карта в качестве шаблона выполняет сопоставление подмножества, но не сразу после назначения переменной:
match?(%{x: 1}, %{x: 1, y: 2})
#=> true
attrs = %{x: 1}
match?(^attrs, %{x: 1, y: 2})
#=> false
Оператор привязки будет проверять, равны ли значения, используя ===/2, а шаблоны имеют свои правила при сопоставлении карт, списков и т. д. Такое поведение не специфично для match?/2. Следующий код также вызывает исключение:
attrs = %{x: 1}
^attrs = %{x: 1, y: 2}
#=> (MatchError) no match of right hand side value: %{x: 1, y: 2} max(first, second)Source
@spec max(first, second) :: first | second when first: term(), second: term()
Возвращает наибольшее из двух заданных терминов в соответствии с их структурным сравнением.
Если термины сравниваются как равные, возвращается первый.
Выполняется структурное сравнение, где все термины Elixir могут быть сравнены друг с другом. Дополнительную информацию см. в разделе «Структурное сравнение».
Встраивается компилятором.
Примеры
iex> max(1, 2) 2 iex> max(:a, :b) :b
min(first, second)Source
@spec min(first, second) :: first | second when first: term(), second: term()
Возвращает наименьшее из двух заданных терминов в соответствии с их структурным сравнением.
Если термины сравниваются как равные, возвращается первый.
Выполняется структурное сравнение, где все термины Elixir могут быть сравнены друг с другом. Дополнительную информацию см. в разделе «Структурное сравнение».
Встраивается компилятором.
Примеры
iex> min(1, 2)
1
iex> min("foo", "bar")
"bar" pop_in(path)Source
Удаляет ключ из вложенной структуры по заданному 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)Source
@spec 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)Source
@spec 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)Source
Вставляет значение во вложенную структуру по заданному 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)Source
@spec 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, будет выброшено исключение:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users, ["jane", :age], "oops")
** (ArgumentError) could not put/update key :age on a nil value raise(message)Source
Вызывает исключение.
Если message является строкой, генерирует исключение RuntimeError с указанным сообщением.
Если message является атомом, вызывает raise/2 с атомом в качестве первого аргумента и [] в качестве второго.
Если message является структурой исключения, она вызывается как есть.
Если message — что-то другое, 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)Source
Вызывает исключение.
Вызывает функцию exception/1 для заданного аргумента (который должен быть именем модуля, например, ArgumentError или RuntimeError), передавая attributes для получения структуры исключения.
Любой модуль, содержащий вызов макроса defexception/1, автоматически реализует обработчик Exception.exception/1, ожидаемый функцией raise/2. Дополнительная информация находится в defexception/1.
Примеры
iex> raise(ArgumentError, "Sample") ** (ArgumentError) Sample
reraise(message, stacktrace)Source
Вызывает исключение, сохраняя предыдущий стек вызовов.
Работает как raise/1, но не генерирует новый стек вызовов.
Обратите внимание, что __STACKTRACE__ может использоваться внутри catch/rescue для извлечения текущего стека вызовов.
Примеры
try do
raise "oops"
rescue
exception ->
reraise exception, __STACKTRACE__
end reraise(exception, attributes, stacktrace)Source
Вызывает исключение, сохраняя предыдущий стек вызовов.
reraise/3 работает как reraise/2, за исключением того, что аргументы передаются функции exception/1 так, как описано в raise/2.
Примеры
try do
raise "oops"
rescue
exception ->
reraise WrapperError, [exception: exception], __STACKTRACE__
end send(dest, message)Source
@spec send(dest :: Process.dest(), message) :: message when message: any()
Отправляет сообщение заданному dest и возвращает переданное сообщение.
dest может быть удалённым или локальным PID, локальным портом, локально зарегистрированным именем или кортежем в виде {registered_name, node} для зарегистрированного имени на другом узле.
Встроен в компилятор.
Примеры
iex> send(self(), :hello) :hello
sigil_C(term, modifiers)Source
Обрабатывает сигил ~C для списков символов.
Возвращает список символов без интерполяций и без управляющих последовательностей, кроме экранирования закрывающего символа сигила.
Примеры
iex> ~C(foo)
'foo'
iex> ~C(f#{o}o)
'f\#{o}o' sigil_c(term, modifiers)Source
Обрабатывает сигил ~c для списков символов.
Возвращает список символов, как если бы это была строка в одинарных кавычках, снимая экранирование символов и заменяя интерполяции.
Примеры
iex> ~c(foo)
'foo'
iex> ~c(f#{:o}o)
'foo'
iex> ~c(f\#{:o}o)
'f\#{:o}o' sigil_D(date_string, modifiers)Source
Обрабатывает сигил ~D для дат.
По умолчанию этот сигил использует встроенный Calendar.ISO, который требует, чтобы даты были написаны в формате ISO8601:
~D[yyyy-mm-dd]
например:
~D[2015-01-13]
Если вы используете альтернативные календари, можно использовать любое представление, главное следовать за представлением пробелом и именем календаря:
~D[SOME-REPRESENTATION My.Alternative.Calendar]
Вариант с маленькой буквой ~d не существует, так как интерполяция и экранирование символов не полезны для сигилов дат.
Дополнительная информация о датах находится в модуле Date.
Примеры
iex> ~D[2015-01-13] ~D[2015-01-13]
sigil_N(naive_datetime_string, modifiers)Source
Обрабатывает сигил ~N для наивных дат и времени.
По умолчанию этот сигил использует встроенный Calendar.ISO, который требует, чтобы наивные даты и время были написаны в формате ISO8601:
~N[yyyy-mm-dd hh:mm:ss] ~N[yyyy-mm-dd hh:mm:ss.ssssss] ~N[yyyy-mm-ddThh:mm:ss.ssssss]
например:
~N[2015-01-13 13:00:07] ~N[2015-01-13T13:00:07.123]
Если вы используете альтернативные календари, можно использовать любое представление, главное следовать за представлением пробелом и именем календаря:
~N[SOME-REPRESENTATION My.Alternative.Calendar]
Вариант с маленькой буквой ~n не существует, так как интерполяция и экранирование символов не полезны для сигилов дат и времени.
Дополнительная информация о наивных датах и времени находится в модуле NaiveDateTime.
Примеры
iex> ~N[2015-01-13 13:00:07] ~N[2015-01-13 13:00:07] iex> ~N[2015-01-13T13:00:07.001] ~N[2015-01-13 13:00:07.001]
sigil_R(term, modifiers)Source
Обрабатывает сигил ~R для регулярных выражений.
Возвращает шаблон регулярного выражения без интерполяций и без экранирования символов. Он всё ещё поддерживает экранирование токенов Regex (например, экранирование + или ?) и требует экранирования закрывающего символа сигила, если он встречается в регулярном выражении.
Дополнительная информация о регулярных выражениях находится в модуле Regex.
Примеры
iex> Regex.match?(~R(f#{1,3}o), "f#o")
true sigil_r(term, modifiers)Source
Обрабатывает сигил ~r для регулярных выражений.
Возвращает шаблон регулярного выражения, снимая экранирование символов и заменяя интерполяции.
Дополнительная информация о регулярных выражениях находится в модуле Regex.
Примеры
iex> Regex.match?(~r/foo/, "foo")
true
iex> Regex.match?(~r/a#{:b}c/, "abc")
true
Хотя сигил ~r позволяет использовать скобки и квадратные скобки в качестве разделителей, предпочтительнее использовать " или / для избежания конфликтов экранирования с зарезервированными символами регулярных выражений.
sigil_S(term, modifiers)Source
Обрабатывает сигил ~S для строк.
Возвращает строку без интерполяций и без экранирования символов, кроме экранирования закрывающего символа сигила.
Примеры
iex> ~S(foo)
"foo"
iex> ~S(f#{o}o)
"f\#{o}o"
iex> ~S(\o/)
"\\o/"
Однако, если вы хотите повторно использовать сам символ сигила в строке, вам нужно экранировать его:
iex> ~S((\)) "()"
sigil_s(term, modifiers)Source
Обрабатывает сигил ~s для строк.
Возвращает строку, как если бы это была строка в двойных кавычках, снимая экранирование символов и заменяя интерполяции.
Примеры
iex> ~s(foo)
"foo"
iex> ~s(f#{:o}o)
"foo"
iex> ~s(f\#{:o}o)
"f\#{:o}o" sigil_T(time_string, modifiers)Source
Обрабатывает сигил ~T для временных значений.
По умолчанию этот сигил использует встроенный Calendar.ISO, который требует, чтобы время было записано в формате ISO8601:
~T[hh:mm:ss] ~T[hh:mm:ss.ssssss]
например:
~T[13:00:07] ~T[13:00:07.123]
Если вы используете альтернативные календари, можно использовать любое представление, главное следовать за представлением пробелом и именем календаря:
~T[SOME-REPRESENTATION My.Alternative.Calendar]
Вариант с маленькой буквой ~t не существует, так как интерполяция и экранирование символов не полезны для сигилов времени.
Дополнительная информация о времени находится в модуле Time.
Примеры
iex> ~T[13:00:07] ~T[13:00:07] iex> ~T[13:00:07.001] ~T[13:00:07.001]
sigil_U(datetime_string, modifiers)Source
Обрабатывает сигил ~U для создания объекта UTC DateTime.
По умолчанию, этот сигил использует встроенный Calendar.ISO, который требует, чтобы даты и времена UTC были записаны в формате ISO8601:
~U[yyyy-mm-dd hh:mm:ssZ] ~U[yyyy-mm-dd hh:mm:ss.ssssssZ] ~U[yyyy-mm-ddThh:mm:ss.ssssss+00:00]
например:
~U[2015-01-13 13:00:07Z] ~U[2015-01-13T13:00:07.123+00:00]
Если вы используете альтернативные календари, можно использовать любое представление, но необходимо указать его, добавив после значения пробел и имя календаря:
~U[SOME-REPRESENTATION My.Alternative.Calendar]
Указанное datetime_string значение должно содержать смещение "Z" или "00:00", указывающее на UTC, иначе произойдёт ошибка.
Нижний регистр ~u варианта не существует, так как символы интерполяции и экранирования не используются в сигилах для дат и времён.
Дополнительную информацию о датах и временах можно найти в модуле DateTime.
Примеры
iex> ~U[2015-01-13 13:00:07Z] ~U[2015-01-13 13:00:07Z] iex> ~U[2015-01-13T13:00:07.001+00:00] ~U[2015-01-13 13:00:07.001Z]
sigil_W(term, modifiers)Source
Обрабатывает сигил ~W для списка слов.
Возвращает список «слов», разделённых пробелами, без интерполяции и без экранирования символов, за исключением экранирования символа закрытия сигила.
Модификаторы
-
s: слова в списке — строки (по умолчанию) -
a: слова в списке — атомы -
c: слова в списке — списки символов
Примеры
iex> ~W(foo #{bar} baz)
["foo", "\#{bar}", "baz"] sigil_w(term, modifiers)Source
Обрабатывает сигил ~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]
iex> ~w(foo bar baz)c
['foo', 'bar', 'baz'] spawn(fun)Source
@spec 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)Source
@spec spawn(module(), atom(), list()) :: pid()
Запускает заданную функцию fun из заданного модуля module, передавая ей заданные аргументы args, и возвращает её PID.
Разработчики обычно не используют функции spawn, а вместо этого используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
См. модуль Process для получения дополнительных функций, связанных с процессами.
Встроенная компилятором.
Примеры
spawn(SomeModule, :function, [1, 2, 3])
spawn_link(fun)Source
@spec 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)Source
@spec 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)Source
@spec 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)Source
@spec spawn_monitor(module(), atom(), list()) :: {pid(), reference()} Запускает заданный модуль и функцию, передавая заданные аргументы, отслеживает её и возвращает её PID и ссылку на отслеживание.
Разработчики обычно не используют функции spawn, а вместо этого используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
См. модуль Process для получения дополнительных функций, связанных с процессами.
Встроенная компилятором.
Примеры
spawn_monitor(SomeModule, :function, [1, 2, 3])
struct(struct, fields \\ [])Source
@spec struct(module() | struct(), Enumerable.t()) :: struct()
Создаёт и обновляет структуру.
Аргумент struct может быть атомом (который определяет defstruct) или самой структурой. Второй аргумент — любой Enumerable, который генерирует пары ключ-значение (кортежи из двух элементов) во время перебора.
Ключи в Enumerable, которые не существуют в структуре, автоматически отбрасываются. Обратите внимание, что ключи должны быть атомами, так как только атомы разрешены при определении структуры. Если ключи в Enumerable дублируются, будет использоваться последняя запись (то же поведение, что и у Map.new/1).
Эта функция полезна для динамического создания и обновления структур, а также для преобразования карт в структуры; в последнем случае просто вставка соответствующего :__struct__ поля в карту может быть недостаточно, и вместо этого следует использовать struct/2.
Примеры
defmodule User do
defstruct name: "john"
end
struct(User)
#=> %User{name: "john"}
opts = [name: "meg"]
user = struct(User, opts)
#=> %User{name: "meg"}
struct(user, unknown: "value")
#=> %User{name: "meg"}
struct(User, %{name: "meg"})
#=> %User{name: "meg"}
# String keys are ignored
struct(User, %{"name" => "meg"})
#=> %User{name: "john"} struct!(struct, fields \\ [])Source
@spec struct!(module() | struct(), Enumerable.t()) :: struct()
Аналогично struct/2, но проверяет валидность ключей.
Функция struct!/2 эмулирует поведение структур на этапе компиляции. Это означает, что:
при создании структуры, как в
struct!(SomeStruct, key: :value), она эквивалентна%SomeStruct{key: :value}, и, следовательно, эта функция проверит, относится ли каждая пара ключ-значение к структуре. Если структура требует какой-либо ключ через@enforce_keys, они также будут проверены;при обновлении структуры, как в
struct!(%SomeStruct{}, key: :value), она эквивалентна%SomeStruct{struct | key: :value}, и, следовательно, эта функция проверит, относится ли каждая пара ключ-значение к структуре. Однако обновление структур не требует проверки ключей, так как ключи проверяются только при создании;
tap(value, fun)Source
Передает первый аргумент, value, во второй аргумент, функцию fun, и возвращает value само.
Полезно для запуска синхронных побочных эффектов в конвейере, используя оператор |>/2.
Примеры
iex> tap(1, fn x -> x + 1 end) 1
Чаще всего это используется в конвейерах, используя оператор |>/2. Например, предположим, что вам нужно проверить часть структуры данных. Вы могли бы написать:
%{a: 1}
|> Map.update!(:a, & &1 + 2)
|> tap(&IO.inspect(&1.a))
|> Map.update!(:a, & &1 * 2) then(value, fun)Source
Передает первый аргумент, value, во второй аргумент, функцию fun, и возвращает результат вызова fun.
Другими словами, она вызывает функцию fun с value в качестве аргумента и возвращает её результат.
Это чаще всего используется в конвейерах, используя оператор |>/2, позволяя передавать значение в функцию, не ограничиваясь её первым аргументом.
Примеры
iex> 1 |> then(fn x -> x * 2 end) 2 iex> 1 |> then(fn x -> Enum.drop(["a", "b", "c"], x) end) ["b", "c"]
throw(term)Source
@spec throw(term()) :: no_return()
Нелокальное возвращение из функции.
Использование throw/1 обычно не рекомендуется, так как оно позволяет функции выйти за пределы своего обычного потока выполнения, что может затруднить чтение кода. Кроме того, все брошенные значения должны быть перехвачены try/catch. Смотрите try/1 для получения дополнительной информации.
Встраивается компилятором.
to_charlist(term)Source
Преобразует заданный термин в charlist в соответствии с протоколом List.Chars.
Примеры
iex> to_charlist(:foo) 'foo'
to_string(term)Source
Преобразует аргумент в строку в соответствии с протоколом String.Chars.
Эта функция вызывается при интерполяции строк.
Примеры
iex> to_string(:foo) "foo"
unless(condition, clauses)Source
Обеспечивает макрос 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)Source
Обновляет вложенную структуру с помощью данной функции 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)Source
@spec update_in(Access.t(), [term(), ...], (term() -> term())) :: Access.t()
Обновляет ключ вложенной структуры.
Использует модуль Access для обхода структур в соответствии с заданным keys, если key не является функцией. Если ключ является функцией, она будет вызвана как указано в get_and_update_in/3.
data — это вложенная структура (т. е. карта, список ключевых слов или структура, реализующая поведение Access). Аргумент fun получает значение key (или nil, если key отсутствует), а результат заменяет значение в структуре.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users, ["john", :age], &(&1 + 1))
%{"john" => %{age: 28}, "meg" => %{age: 23}}
Обратите внимание, что текущее значение, переданное анонимной функции, может быть nil. Если любое из промежуточных значений равно nil, будет возбуждено исключение:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users, ["jane", :age], & &1 + 1)
** (ArgumentError) could not put/update key :age on a nil value use(module, opts \\ [])Source
Использует данный модуль в текущем контексте.
При вызове:
use MyModule, some: :options
Elixir вызовет MyModule.__using__/1, передав второй аргумент use в качестве своего аргумента. Поскольку __using__/1 обычно является макросом, применяются все обычные правила для макросов, а её возвращаемое значение должно быть цитируемым кодом, который затем вставляется туда, где вызывается use/2.
Примечание:
use MyModuleработает как точка вставки кода в вызывающий код. Учитывая, что вызывающий кодuse MyModuleимеет небольшой контроль над тем, как вставляется код,use/2следует использовать с осторожностью. Если возможно, избегайте использования в пользуimport/2илиalias/2в случае возможности.
Примеры
Например, для написания тестовых случаев, используя фреймворк ExUnit, предоставляемый с Elixir, разработчик должен использовать ExUnit.Case модуль:
defmodule AssertionTest do
use ExUnit.Case, async: true
test "always pass" do
assert true
end
end
В этом примере Elixir вызовет макрос __using__/1 в модуле ExUnit.Case с списком ключевых слов [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). Даже в этих случаях определение функций следует рассматривать как «последний выход».
var!(var, context \\ nil)Source
Помечает, что данная переменная не должна подвергаться гигиенизации.
Этот макрос ожидает переменную и обычно вызывается внутри Kernel.SpecialForms.quote/2 для обозначения того, что переменная не должна подвергаться гигиенизации. См. Kernel.SpecialForms.quote/2 для получения дополнительной информации.
Примеры
iex> Kernel.var!(example) = 1 1 iex> Kernel.var!(example) 1
left |> rightSource
Оператор конвейера.
Этот оператор вводит выражение слева в качестве первого аргумента вызова функции справа.
Примеры
iex> [1, [2], 3] |> List.flatten() [1, 2, 3]
Приведённый выше пример эквивалентен вызову List.flatten([1, [2], 3]).
Оператор |>/2 в основном полезен, когда требуется выполнить серию операций, напоминающих конвейер:
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()
Вторая ограничение заключается в том, что Elixir всегда применяет конвейер к вызову функции. Поэтому, чтобы применить конвейер к анонимной функции, необходимо вызвать её:
some_fun = &Regex.replace(~r/l/, &1, "L") "Hello" |> some_fun.()
В качестве альтернативы, можно использовать then/2 для того же результата:
some_fun = &Regex.replace(~r/l/, &1, "L") "Hello" |> then(some_fun)
then/2 чаще всего используется, когда вы хотите применить конвейер к функции, но значение ожидается вне первого аргумента, как показано выше. Заменив some_fun его значением, получаем:
"Hello" |> then(&Regex.replace(~r/l/, &1, "L"))
left || rightSource
Логический оператор «или».
Обеспечивает оператор короткого замыкания, который оценивает и возвращает второе выражение только в том случае, если первое выражение не оценивается как истинное значение (то есть, оно равно либо nil или false). В противном случае возвращает первое выражение.
Запрещено в операторах-условиях.
Примеры
iex> Enum.empty?([1]) || Enum.empty?([1]) false iex> List.first([]) || true true iex> Enum.empty?([1]) || 1 1 iex> Enum.empty?([]) || throw(:bad) true
Обратите внимание, что, в отличие от or/2, этот оператор принимает любое выражение в качестве первого аргумента, а не только булевы значения.
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.14.1/Kernel.html