Исходный код Ядро
Kernel — это стандартная среда выполнения Elixir.
Она в основном состоит из:
- базовых языковых примитивов, таких как арифметические операторы, создание процессов, обработка типов данных и другие
- макросов для управления потоком и определения новых функций (модули, функции и т. п.)
- условий для расширения шаблонов сопоставления
Вы можете вызывать функции и макросы Kernel в любом месте кода Elixir без использования префикса Kernel., так как они были автоматически импортированы. Например, в IEx можно вызвать:
iex> is_number(13) true
Если вы не хотите импортировать функцию или макрос из Kernel, используйте опцию :except и затем перечислите функцию/макрос по арности:
import Kernel, except: [if: 2, unless: 2]
Дополнительную информацию об импорте см. в import/2.
Elixir также имеет специальные формы, которые всегда импортируются и не могут быть пропущены. Они описаны в Kernel.SpecialForms.
Стандартная библиотека
Kernel предоставляет базовые возможности, на которых построена стандартная библиотека Elixir. Рекомендуется изучить стандартную библиотеку для расширенных функций. Вот основные группы модулей в стандартной библиотеке (этот список не является полным справочником, см. боковую панель документации для всех записей).
Встроенные типы
Следующие модули обрабатывают встроенные типы данных Elixir:
-
Atom— литеральные константы с именем (true,false, иnil— атомы) -
Float— числа с плавающей точкой -
Function— ссылка на фрагмент кода, созданный с помощью специальной формыfn/1 -
Integer— целые числа (не дроби) -
List— коллекции переменного числа элементов (связанные списки) -
Map— коллекции пар ключ-значение -
Process— лёгкие потоки выполнения -
Port— механизмы взаимодействия с внешним миром -
Tuple— коллекции фиксированного числа элементов
Существуют два типа данных без сопроводительного модуля:
- Битовая строка — последовательность битов, созданная с помощью
<<>>/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— преобразует типы данных в их представление во внешнем мире как charlists (не связанные с программированием) -
String.Chars— преобразует типы данных в их представление во внешнем мире как строки (не связанные с программированием)
Функциональность, основанная на процессах и ориентированная на приложения
Следующие модули основаны на процессах, чтобы обеспечить конкурентность, отказоустойчивость и многое другое.
-
Agent— процесс, который инкапсулирует изменяемое состояние -
Application— функции для запуска, остановки и настройки приложений -
GenServer— общий API клиент-сервер -
Registry— хранилище ключ-значение на основе процессов -
Supervisor— процесс, ответственный за запуск, надзор и остановку других процессов -
Task— процесс, выполняющий вычисления -
Task.Supervisor— супервайзер для управления задачами исключительно
Вспомогательные документы
В разделе «Страницы» в боковой панели вы найдете учебники, руководства и справочные документы, которые более подробно описывают семантику и поведение Elixir. Это:
- Совместимость и устаревшие функции — список совместимости между каждой версией Elixir и Erlang/OTP, схема релизов; список всех устаревших функций, когда они устарели и альтернативы
- Руководства по разработке библиотек — общие руководства, антипаттерны и правила для авторов библиотек
- Конвенции именования — конвенции именования для кода Elixir
- Справочник по операторам — список всех операторов Elixir и их приоритетов
- Шаблоны и условия — введение в шаблоны, условия и расширения
- Справочник по синтаксису — справочник по синтаксису языка
- Справочник по типам — спецификации типов и функций, включая список типов
- Синтаксис Unicode — обзор поддержки Unicode в Elixir
Условные операторы
Этот модуль включает встроенные условия, используемые разработчиками Elixir. Это предопределённый набор функций и макросов, которые дополняют сопоставление с образцом, обычно вызываемые после оператора when. Например:
def drive(%User{age: age}) when age >= 16 do
...
end
Приведенная выше строка выполнится только в том случае, если возрасту пользователя 16 лет или больше. Условия также поддерживают объединение нескольких условий с помощью and и or. Всё условие истинно, если все выражения условия будут истинными true. Более полное введение в условия можно найти на странице Шаблоны и условия.
Истинностные и ложные значения
Помимо булевых значений true и false, в Elixir существует понятие «истинностного» или «ложного» значения.
- значение истинно, когда оно не
falseи неnil - значение ложно, когда оно либо
false, либоnil
Elixir имеет функции, такие как and/2, которые работают только с булевыми значениями, но также функции, которые работают с этими истинностными/ложными значениями, такие как &&/2 и !/1.
Структурное сравнение
Функции в этом модуле выполняют структурное сравнение. Это позволяет сравнивать разные типы данных с помощью операторов сравнения:
1 < :an_atom
Это возможно, чтобы разработчики Elixir могли создавать коллекции, такие как словари и упорядоченные множества, которые хранят смесь типов данных. Чтобы понять, почему это важно, давайте обсудим два типа сравнений, которые мы находим в программном обеспечении: структурное и семантическое.
Структурное означает, что мы сравниваем основанные типы данных, и мы часто хотим, чтобы эти операции были максимально быстрыми, потому что они используются для питания нескольких алгоритмов и структур данных в языке. Семантическое сравнение озабочено тем, что представляет каждый тип данных. Например, семантически говоря, нет смысла сравнивать Time со Date.
Один пример, показывающий различия между структурным и семантическим сравнением, — это строки: «alien» сортируется меньше, чем «office» ("alien" < "office") но «álien» больше, чем «office». Это происходит потому, что < сравнивает основанные байты, которые образуют строку. Если вы делаете алфавитный список, то вы можете захотеть, чтобы «álien» также появлялся перед «office».
Это означает, что сравнения в Elixir структурные, так как они преследуют цель сравнивать типы данных максимально эффективно, чтобы создавать гибкие и производительные структуры данных. Это различие особенно важно для функций, которые обеспечивают упорядочение, такие как >/2, </2, >=/2, <=/2, min/2 и max/2. Например:
~D[2017-03-31] > ~D[2017-04-01]
вернёт true потому что структурное сравнение сравнивает поле :day перед :month или :year. К счастью, компилятор Elixir обнаружит, когда сравниваются структуры или когда сравнивается код, который всегда истин или ложен, и выведет соответствующее предупреждение.
Для выполнения семантических сравнений соответствующие типы данных предоставляют функцию compare/2, такую как Date.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]
Второй аргумент — это именно модуль, используемый для семантического сравнения. Сохранение этого различия важно, потому что если бы семантическое сравнение использовалось по умолчанию для реализации структур данных и алгоритмов, они могли бы стать на порядки медленнее!
Наконец, обратите внимание, что существует общий порядок структурной сортировки, называемый «Порядок терминов», определённый ниже. Этот порядок предоставлен для справки, разработчики Elixir не обязаны его запоминать.
Порядок терминов
number < atom < reference < function < port < pid < tuple < map < list < bitstring
При сравнении двух чисел разных типов (число — это либо целое число, либо число с плавающей точкой), всегда происходит преобразование в тип с большей точностью, за исключением случаев, когда используемый оператор сравнения — это ===/2 или !==. Число с плавающей точкой будет считаться более точным, чем целое число, за исключением случаев, когда число с плавающей точкой больше/меньше +/-9007199254740992.0 соответственно, в этом случае все значащие цифры числа с плавающей точкой находятся слева от десятичной точки. Это поведение существует для того, чтобы сохранялась транзитивность сравнения больших чисел.
Типы коллекций сравниваются по следующим правилам:
- Кортежи сравниваются по размеру, а затем по элементам попарно.
- Карты сравниваются по размеру, затем по ключам в порядке возрастания порядка терминов, а затем по значениям в порядке ключей. В случае упорядочения ключей карт целые числа всегда считаются меньше чисел с плавающей точкой.
- Списки сравниваются попарно по элементам.
- Битовые строки сравниваются байт за байтом, неполные байты сравниваются бит за битом.
- Атомы сравниваются по своему строковому значению, по кодовым точкам.
Примеры
Мы можем проверить истинность значения, дважды используя функцию !/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, size)
Извлекает часть бинарного по
startсsize.- 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_non_struct_map(term)
Возвращает
trueеслиtermэто карта, которая не является структурой, иначе возвращает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)
Возвращает длину
list.- map_size(map)
Возвращает размер карты.
- node()
Возвращает атом, представляющий имя локального узла. Если узел не активен, возвращается
:nonode@nohostвместо этого.- node(arg)
Возвращает узел, где расположен заданный аргумент. Аргументом может быть PID, ссылка или порт. Если локальный узел не активен, возвращается
:nonode@nohost.- not value
Строго булевый оператор «не».
- left or right
Строго булевый оператор «или».
- rem(dividend, divisor)
Вычисляет остаток от целочисленного деления.
- round(number)
Округляет число до ближайшего целого.
- self()
Возвращает PID (идентификатор процесса) вызывающего процесса.
- tl(list)
Возвращает хвост списка. Вызывает
ArgumentErrorесли список пуст.- trunc(number)
Возвращает целую часть
number.- tuple_size(tuple)
Возвращает размер кортежа.
Функции
- 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
Оператор соответствия текста. Сопоставляет терм в
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(path)
Получает ключ из вложенной структуры по заданному
path, с обработкой nil.- get_in(data, keys)
Получает значение из вложенной структуры с обработкой nil.
- 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)
Задает значение в вложенную структуру по заданному
path.- put_in(data, keys, value)
Задает значение в вложенную структуру.
- raise(message)
Вызывает исключение.
- raise(exception, attributes)
Вызывает исключение.
- reraise(message, stacktrace)
Вызывает исключение, сохраняя предыдущий стек вызовов.
- reraise(exception, attributes, stacktrace)
Вызывает исключение, сохраняя предыдущий стек вызовов.
- send(dest, message)
Отправляет сообщение заданному
destи возвращает полученное сообщение.- sigil_C(term, modifiers)
Обрабатывает сигил
~Cдля списков символов.- sigil_c(term, modifiers)
Обрабатывает сигил
~cдля списков символов.- sigil_D(date_string, modifiers)
Обрабатывает сигил
~Dдля дат.- sigil_N(naive_datetime_string, modifiers)
Обрабатывает сигил
~Nдля простых дат и времени.- sigil_r(term, modifiers)
Обрабатывает сигил
~rдля регулярных выражений.- sigil_S(term, modifiers)
Обрабатывает сигил
~Sдля строк.- sigil_s(term, modifiers)
Обрабатывает сигил
~sдля строк.- sigil_T(time_string, modifiers)
Обрабатывает сигил
~Tдля времени.- sigil_U(datetime_string, modifiers)
Обрабатывает сигил
~Uдля создания UTCDateTime.- sigil_W(term, modifiers)
Обрабатывает сигил
~Wдля списков слов.- sigil_w(term, modifiers)
Обрабатывает сигил
~wдля списков слов.- spawn(fun)
Запускает заданную функцию и возвращает её PID.
- spawn(module, fun, args)
Запускает заданную функцию
funиз заданногоmodule, передавая ей заданныеargs, и возвращает её PID.- spawn_link(fun)
Запускает заданную функцию, связывая её с текущим процессом, и возвращает её PID.
- spawn_link(module, fun, args)
Запускает заданную функцию
funиз заданногоmodule, передавая ей заданныеargs, связывая её с текущим процессом, и возвращает её PID.- spawn_monitor(fun)
Запускает заданную функцию, отслеживает её и возвращает её PID и ссылку на отслеживание.
- spawn_monitor(module, fun, args)
Запускает заданный модуль и функцию, передавая заданные аргументы, отслеживает её и возвращает её PID и ссылку на отслеживание.
- struct(struct, fields \\ [])
Создаёт и обновляет структуру.
- struct!(struct, fields \\ [])
Аналогично
struct/2, но проверяет корректность ключей.- tap(value, fun)
Передает первый аргумент,
value, во второй аргумент, функциюfun, и возвращаетvalueсамо.- then(value, fun)
Передает первый аргумент,
value, во второй аргумент, функциюfun, и возвращает результат вызоваfun.- throw(term)
Нелокальное возвращение из функции.
- to_charlist(term)
Преобразует заданный термин в список символов в соответствии с протоколом
List.Chars.- to_string(term)
Преобразует аргумент в строку в соответствии с протоколом
String.Chars.- to_timeout(duration)
Создаёт таймаут в миллисекундах из заданных компонентов, длительности или таймаута.
- unless(condition, clauses)
Предоставляет макрос
unless.- update_in(path, fun)
Обновляет вложенную структуру по заданному
path.- update_in(data, keys, fun)
Обновляет ключ в вложенной структуре.
- use(module, opts \\ [])
Использует указанный модуль в текущем контексте.
- var!(var, context \\ nil)
Помечает, что указанная переменная не должна быть санратизирована.
- left |> right
Оператор конвейера.
- left || right
Булевый оператор "или".
Операторы
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 является false, возвращает false, иначе возвращает right.
Требуется, чтобы только left операнд был булевым, так как происходит короткое замыкание. Если 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(бинарный, начало, размер)Исходный код
@spec binary_part(binary(), non_neg_integer(), integer()) :: binary()
Извлекает часть бинарного start с size.
Если start или size ссылаются каким-либо образом за пределы бинарного, возникает исключение ArgumentError.
Разрешено в тестах стражей. Встроенный компилятором.
Примеры
iex> binary_part("foo", 1, 2)
"oo"
Отрицательное size может быть использовано для извлечения байтов, которые предшествуют байту в start:
iex> binary_part("Hello", 5, -3)
"llo"
Исключение ArgumentError возникает, когда size находится за пределами бинарного:
binary_part("Hello", 0, 10)
** (ArgumentError) argument error bit_size(битовая строка)Исходный код
@spec bit_size(bitstring()) :: non_neg_integer()
Возвращает целое число, представляющее размер bitstring в битах.
Разрешено в тестах стражей. Встроенный компилятором.
Примеры
iex> bit_size(<<433::16, 3::3>>) 19 iex> bit_size(<<1, 2, 3>>) 24
byte_size(битовая строка)Исходный код
@spec byte_size(bitstring()) :: non_neg_integer()
Возвращает количество байтов, необходимых для хранения bitstring.
То есть, если количество битов в bitstring не делится на 8, результирующее количество байтов округляется вверх (до большего значения). Эта операция выполняется за постоянное время.
Разрешено в тестах стражей. Встроенный компилятором.
Примеры
iex> byte_size(<<433::16, 3::3>>) 3 iex> byte_size(<<1, 2, 3>>) 3
ceil(число)Исходный код
@spec ceil(number()) :: integer()
Возвращает наименьшее целое число, большее или равное number.
Если нужно выполнить операцию ceil для других десятичных знаков, используйте Float.ceil/2 вместо этого.
Разрешено в тестах стражей. Встроенный компилятором.
Примеры
iex> ceil(10) 10 iex> ceil(10.1) 11 iex> ceil(-10.1) -10
div(делимое, делитель)Исходный код
@spec div(integer(), neg_integer() | pos_integer()) :: integer()
Выполняет целочисленное деление.
Возбуждает исключение ArithmeticError, если один из аргументов не является целым числом или когда divisor равно 0.
div/2 выполняет обрезанное целочисленное деление. Это означает, что результат всегда округляется к нулю.
Если нужно выполнить деление с округлением к меньшему целому (к отрицательной бесконечности), используйте Integer.floor_div/2 вместо этого.
Разрешено в тестах стражей. Встроенный компилятором.
Примеры
div(5, 2) #=> 2 div(6, -4) #=> -1 div(-99, 2) #=> -49 div(100, 0) ** (ArithmeticError) bad argument in arithmetic expression
elem(кортеж, индекс)Исходный код
@spec elem(tuple(), non_neg_integer()) :: term()
Возвращает элемент с нулевым индексом в tuple.
Возбуждает ArgumentError, когда индекс отрицательный или выходит за пределы диапазона элементов кортежа.
Разрешено в тестах стражей. Встроенный компилятором.
Примеры
tuple = {:foo, :bar, 3}
elem(tuple, 1)
#=> :bar
elem({}, 0)
** (ArgumentError) argument error
elem({:foo, :bar}, 2)
** (ArgumentError) argument error floor(число)Исходный код
@spec floor(number()) :: integer()
Возвращает наибольшее целое число, меньшее или равное number.
Если нужно выполнить операцию floor для других десятичных знаков, используйте Float.floor/2 вместо этого.
Разрешено в тестах стражей. Встроенный компилятором.
Примеры
iex> floor(10) 10 iex> floor(9.7) 9 iex> floor(-9.7) -10
hd(список)Исходный код
@spec hd(nonempty_maybe_improper_list(elem, any())) :: elem when elem: term()
Возвращает голову списка. Возбуждает ArgumentError, если список пустой.
Голова списка — это его первый элемент.
Работает со списками неправильной формы.
Разрешено в тестах стражей. Встроенный компилятором.
Примеры
hd([1, 2, 3, 4]) #=> 1 hd([1 | 2]) #=> 1
При передаче пустого списка возникает:
hd([]) ** (ArgumentError) argument error
левая часть в правойИсходный код
Оператор принадлежности.
Проверяет, является ли элемент слева элементом коллекции справа.
Примеры
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(термин)Исходный код
@spec is_atom(term()) :: boolean()
Возвращает true, если term является атомом, иначе возвращает false.
Заметьте, что true, false, и nil являются атомами в Elixir, а также именами модулей. Поэтому эта функция вернёт true для всех этих значений.
Разрешено в тестах стражей. Встроенный компилятором.
Примеры
iex> is_atom(:name)
true
iex> is_atom(false)
true
iex> is_atom(AnAtom)
true
iex> is_atom("string")
false is_binary(термин)Исходный код
@spec is_binary(term()) :: boolean()
Возвращает true если term является бинарным, иначе возвращает false.
Бинарный всегда содержит целое число байтов.
Разрешено в тестах стражей. Встроенный компилятором.
Примеры
iex> is_binary("foo")
true
iex> is_binary(<<1::3>>)
false is_bitstring(термин)Исходный код
@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.
Разрешено в тестах-ограничителях. Встраивается компилятором.
Структуры — это карты
Структуры также являются картами, и многие структуры данных Elixir реализованы с использованием структур:
Ranges,Regexes,Dates...iex> is_map(1..10) true iex> is_map(~D[2024-04-18]) trueЕсли вы хотите проверить именно карты, которые не являются структурами, используйте
is_non_struct_map/1вместо этого.iex> is_non_struct_map(1..10) false
is_map_key(map, key)Source
@spec is_map_key(map(), term()) :: boolean()
Возвращает true если key это ключ в map, в противном случае возвращает false.
Вызывает BadMapError, если первый элемент не является картой.
Разрешено в тестах-ограничителях. Встраивается компилятором.
Примеры
iex> is_map_key(%{a: "foo", b: "bar"}, :a)
true
iex> is_map_key(%{a: "foo", b: "bar"}, :c)
false is_nil(term)Source
Возвращает true если term это nil, false в противном случае.
Разрешено в защитных конструкциях.
Примеры
iex> is_nil(1) false iex> is_nil(nil) true
is_non_struct_map(term)Source
Возвращает true если term это карта, которая не является структурой, в противном случае возвращает false.
Разрешено в тестах-ограничителях.
Примеры
iex> is_non_struct_map(%{})
true
iex> is_non_struct_map(URI.parse("/"))
false
iex> is_non_struct_map(nil)
false 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.
is_struct/2 не проверяет, что name существует и является корректной структурой. Если вам нужны такие проверки, необходимо вместо этого сопоставить структуру с шаблоном, например, match?(%URI{}, arg).
Разрешено в тестах-ограничителях.
Примеры
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()
Возвращает атом, представляющий имя локального узла. Если узел не активен, возвращается :nonode@nohost.
Разрешено в тестах охранных условий. Встроенно компилятором.
node(arg)Source
@spec node(pid() | reference() | port()) :: node()
Возвращает узел, где находится данный аргумент. Аргумент может быть PID, ссылкой или портом. Если локальный узел не активен, возвращается :nonode@nohost.
Разрешено в тестах охранных условий. Встроенно компилятором.
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(dividend, divisor)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(number)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(list)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(number)Source
@spec trunc(number()) :: integer()
Возвращает целую часть number.
Разрешено в тестах охранных условий. Встроено компилятором.
Примеры
iex> trunc(5.4) 5 iex> trunc(-5.99) -5 iex> trunc(-5) -5
tuple_size(tuple)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()
@spec integer() ** float() :: float()
@spec float() ** integer() :: float()
Оператор возведения в степень.
Принимает два числа в качестве входных данных. Если оба являются целыми числами, а правая часть (экспонента) также больше или равна 0, то результат также будет целым числом. В противном случае возвращается число с плавающей точкой.
Примеры
iex> 2 ** 2 4 iex> 2 ** -4 0.0625 iex> 2.0 ** 2 4.0 iex> 2 ** 2.0 4.0
left ++ rightSource
@spec [] ++ a :: a when a: term()
@spec [...] ++ term() :: maybe_improper_list()
Оператор конкатенации списков. Объединяет правильный список и элемент, возвращая список.
Сложность a ++ b пропорциональна length(a), поэтому избегайте многократного добавления элементов в списки произвольной длины, например, list ++ [element]. Вместо этого рассмотрите добавление в начало через [element | rest] и последующее обращение списка.
Если операнд right не является правильным списком, возвращается неправильный список. Если операнд left не является правильным списком, генерируется исключение ArgumentError. Если операнд left — пустой список, возвращается операнд right.
Встроен в компилятор.
Примеры
iex> [1] ++ [2, 3]
[1, 2, 3]
iex> ~c"foo" ++ ~c"bar"
~c"foobar"
# a non-list on the right will return an improper list
# with said element at the end
iex> [1, 2] ++ 3
[1, 2 | 3]
iex> [1, 2] ++ {3, 4}
[1, 2 | {3, 4}]
# improper list on the right will return an improper list
iex> [1] ++ [2 | 3]
[1, 2 | 3]
# empty list on the left will return the right operand
iex> [] ++ 1
1
Оператор ++/2 ассоциативен справа, что означает:
iex> [1, 2, 3] -- [1] ++ [2] [3]
Что эквивалентно:
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()
Оператор совпадения. Проверяет терм слева на соответствие регулярному выражению или строке справа.
Если справа стоит регулярное выражение, возвращает true если left соответствует выражению справа.
Если справа стоит строка, возвращает 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] alias!(alias)Source
При использовании внутри цитирования отмечает, что заданный псевдоним не должен быть гигиенизирован. Это означает, что псевдоним будет расширен при расширении макроса.
См. 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 в IEx
Вы можете разрешить IEx заменять dbg своим бэкэндом IEx.pry/0 вызовом:
$ iex --dbg pry
В таких случаях dbg запустит сеанс pry, где вы сможете взаимодействовать с импортами, псевдонимами и переменными текущей среды в месте вызова dbg.
Если вы вызываете dbg в конце конвейера (используя |>) в IEx, вы можете пройти через каждый шаг конвейера по одному, введя «next» (или «n»).
Обратите внимание dbg поддерживает пошаговое выполнение только для конвейеров (то есть оно может только проходить по тому коду, который видит). Для общего пошагового выполнения можно установить точки останова с помощью IEx.break!/4.
Для получения дополнительной информации см. документацию IEx.
Настройка функции отладки
Одно из преимуществ 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
Обратите внимание, что \\ нельзя использовать с анонимными функциями, поскольку они могут иметь только единственную арность.
Списки ключевых слов с аргументами по умолчанию
Функции, содержащие много аргументов, могут извлечь выгоду из использования списков Keyword для группировки и передачи атрибутов как одного значения.
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:
- должны быть атомами
- могут быть заданы более одного раза
- упорядочены, как указано разработчиком
Имена функций
Имена функций и переменных в Elixir должны начинаться с подчеркивания или буквы Юникода, которая не является заглавной или прописной. Они могут продолжаться с последовательностью букв, цифр и подчеркиваний Юникода. Они могут заканчиваться на ? или !. Конвенции именования Elixir рекомендуют писать имена функций и переменных в формате snake_case.
rescue/catch/after/else
Тела функций поддерживают rescue, catch, after, и else как 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- получает структуру исключения и должна вернуть ее сообщение. Чаще всего исключения имеют поле сообщения, которое по умолчанию доступно через эту функцию. Однако, если у исключения нет поля сообщения, эта функция должна быть реализована явно.
Поскольку исключения являются структурами, 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
Имена модулей и псевдонимы
Имена модулей (и псевдонимы) должны начинаться с заглавной буквы ASCII, за которой могут следовать любые буквы, цифры или символы подчеркивания ASCII. Конвенции именования Elixir рекомендуют использовать CamelCase формат для имён модулей и псевдонимов.
Также можно использовать атомы в качестве имени модуля, хотя они должны содержать только символы ASCII.
Вложенность
Вложение модуля внутри другого модуля влияет на имя вложенного модуля:
defmodule Foo do defmodule Bar do end end
В примере выше создаются два модуля - Foo и Foo.Bar. При вложении Elixir автоматически создаёт псевдоним для внутреннего модуля, позволяя получить доступ ко второму модулю Foo.Bar как к Bar в той же лексической области, где он определён (в модуле Foo). Это происходит только если вложенный модуль определён с помощью псевдонима.
Если модуль Foo.Bar будет перемещён в другое место, ссылки на Bar в модуле Foo необходимо обновить на полное имя (Foo.Bar) или явно установить псевдоним в модуле Foo с помощью 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 Module.concat(["Foo", "Bar"]) 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
Определяет структуру.
Структура — это помеченная карта, которая позволяет разработчикам предоставлять значения по умолчанию для ключей, метки для использования в полиморфных диспетчеризациях и утверждениях на этапе компиляции. Для получения дополнительной информации о структурах, пожалуйста, ознакомьтесь с %/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
Добавьте документацию к структуре с атрибутом @doc, как и к функции.
defmodule Post do @doc "A post. The content should be valid Markdown." 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. Если реализация протокола определяет обратный вызов __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) при завершении процесса теста, чтобы сигнализировать связанным процессам, деревьям супервизора и т. д. о корректном завершении.
Выходы CLI
На основе вышеупомянутых сигналов выхода, если процесс, запущенный из командной строки, завершается с любой из трех вышеперечисленных причин, его выход считается нормальным, и процесс операционной системы завершится со статусом 0.
Однако, возможно настроить сигнал выхода операционной системы, вызвав:
exit({:shutdown, integer})
Это приведет к завершению процесса операционной системы со статусом, заданным integer , одновременно сигнализируя всем связанным процессам Erlang о корректном завершении.
Любая другая причина выхода приведет к завершению процесса операционной системы со статусом 1 и сбою связанных процессов Erlang.
function_exported?(module, function, arity)Source
@spec function_exported?(module(), atom(), arity()) :: boolean()
Возвращает true , если модуль module загружен и содержит публичную function с заданным arity, в противном случае false.
Обратите внимание, что эта функция не загружает модуль в случае, если он не загружен. См. Code.ensure_loaded/1 для получения дополнительной информации.
Встроено компилятором.
Примеры
iex> function_exported?(Enum, :map, 2) true iex> function_exported?(Enum, :map, 10) false iex> function_exported?(List, :to_string, 1) true
get_and_update_in(path, fun)Source
Получает значение и обновляет вложенную структуру данных с помощью заданной path.
Это аналогично get_and_update_in/3, за исключением того, что путь извлекается с помощью макроса, а не передается в виде списка. Например:
get_and_update_in(opts[:foo][:bar], &{&1, &1 + 1})
Эквивалентно:
get_and_update_in(opts, [:foo, :bar], &{&1, &1 + 1})
Это также работает со вложенными структурами и способом указания путей с помощью struct.path.to.value:
get_and_update_in(struct.foo.bar, &{&1, &1 + 1})
Обратите внимание, что для работы этого макроса весь путь должен всегда быть доступен этому макросу. См. раздел «Пути» ниже.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users["john"].age, &{&1, &1 + 1})
{27, %{"john" => %{age: 28}, "meg" => %{age: 23}}}
Пути
Путь может начинаться с переменной, локального или удаленного вызова и должен быть последован одним или несколькими:
foo[bar]- обращается к ключуbarвfoo; в случае, еслиfooравно null, возвращаетсяnilfoo.bar- обращается к полю карты/структуры; в случае отсутствия поля, генерируется ошибка
Вот некоторые допустимые пути:
users["john"][:age] users["john"].age User.all()["john"].age all_users()["john"].age
Вот некоторые недопустимые:
# Does a remote call after the initial value users["john"].do_something(arg1, arg2) # Does not access any key or field users
get_and_update_in(data, keys, fun)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 получает значение key (или nil если key отсутствует) и должен вернуть одно из следующих значений:
двухэлементную кортеж
{current_value, new_value}. В этом случае,current_value- это полученное значение, которое может быть обработано перед возвратом.new_value- это новое значение, которое должно быть сохранено подkey.:pop, что подразумевает удаление текущего значения подkeyиз структуры и его возврат.
Эта функция использует модуль Access для обхода структур в соответствии с заданными keys, если key не является функцией, что подробно описано в последующем разделе.
Примеры
Эта функция полезна, когда необходимо получить текущее значение (или что-то вычисленное в функции от текущего значения) и обновить его одновременно. Например, она может использоваться для чтения текущего возраста пользователя и увеличения его на единицу в одном проходе:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users, ["john", :age], &{&1, &1 + 1})
{27, %{"john" => %{age: 28}, "meg" => %{age: 23}}}
Обратите внимание, что текущее значение, переданное анонимной функции, может быть nil. Если любое из промежуточных значений равно null, будет выброшено исключение:
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) - данные для доступа
- функция, которая должна быть вызвана дальше
Это означает, что get_and_update_in/3 может быть расширена для предоставления пользовательских поисков. Недостатком является то, что функции не могут быть сохранены в качестве ключей в структуре данных, к которой осуществляется доступ.
Когда один из ключей является функцией, функция вызывается. В примере ниже мы используем функцию для получения и инкрементирования всех возрастов внутри списка:
iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> all = fn :get_and_update, data, next ->
...> data |> Enum.map(next) |> Enum.unzip()
...> end
iex> get_and_update_in(users, [all, :age], &{&1, &1 + 1})
{[27, 23], [%{name: "john", age: 28}, %{name: "meg", age: 24}]}
Если значение до вызова функции было nil, функция *получит* nil в качестве значения и должна обработать его соответствующим образом (будь то сбой или предоставление разумного значения по умолчанию).
Модуль Access поставляется со многими удобными функциями доступа, такими как анонимная функция all определенная выше. См. Access.all/0, Access.key/2 и другие в качестве примеров.
get_in(path)Source
Получает ключ из вложенной структуры по заданному path, с обработкой nil-значений.
Это аналогично get_in/2, за исключением того, что путь извлекается с помощью макроса, а не передается в виде списка. Например:
get_in(opts[:foo][:bar])
Эквивалентно:
get_in(opts, [:foo, :bar])
Кроме того, этот макрос может обрабатывать структуры:
get_in(struct.foo.bar)
В случае, если любой из ключей возвращает nil, то будет возвращено nil, и get_in/1 не будет продолжать обход.
Обратите внимание, что для работы этого макроса весь путь должен всегда быть доступен этому макросу. Для получения дополнительной информации о поддерживаемых выражениях пути, пожалуйста, ознакомьтесь со справкой get_and_update_in/2.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users["john"].age)
27
iex> get_in(users["unknown"].age)
nil get_in(data, keys)Source
@spec get_in(Access.t(), [term(), ...]) :: term()
Получает значение из вложенной структуры с безопасной обработкой nil.
Использует модуль Access для обхода структур в соответствии с заданными keys, за исключением случаев, когда key является функцией, подробно описанной в последующем разделе.
Примеры
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
Функции в качестве ключей
Если ключ, переданный функции get_in/2, является функцией, эта функция будет вызвана с тремя аргументами:
- операция (
:get) - данные для доступа
- функция для вызова далее
Это означает, что 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])
Есть два варианта. Поскольку у структур есть предопределённые ключи, мы можем использовать обозначение struct.field:
some_struct.some_key.nested_key
Однако, код выше не сработает, если любое из значений вернёт nil. Если вы также хотите обрабатывать значения nil, вы можете использовать get_in/1:
get_in(some_struct.some_key.nested_key)
Сопоставление с образцом — ещё один вариант обработки таких случаев, что особенно полезно, если вы хотите сопоставить сразу несколько полей или предоставить пользовательские возвращаемые значения:
case some_struct do
%{some_key: %{nested_key: value}} -> value
%{} -> nil
end if(condition, clauses)Source
Предоставляет макрос if/2.
Этот макрос ожидает, что первый аргумент будет условием, а второй — списком ключевых слов. Как правило, разработчики Elixir предпочитают использовать сопоставление с образцом и условия в определениях функций и case/2, так как они лаконичны и точны. Однако не все условия можно выразить через шаблоны и условия, что делает if/2 жизнеспособной альтернативой.
Подобно case/2, любые присваивания в условии будут доступны в обоих разделах, а также после if выражения.
Примеры однострочных выражений
if(foo, do: bar)
В примере выше, bar будет возвращено, если foo вычисляется в истинное значение (ни false ни nil). В противном случае будет возвращено nil.
Опция else может быть указана для задания обратного:
if(foo, do: bar, else: baz)
Примеры с блоками
Также можно передать блок в макрос if/2. Первый пример выше был бы переведён в:
if foo do bar end
Обратите внимание, что do-end становятся разделителями. Второй пример был бы переведён в:
if foo do bar else baz end
Если вы обнаруживаете, что вкладываете условные операторы друг в друга, рассмотрите использование cond/1.
inspect(term, opts \\ [])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(~c"bar")
"~c\"bar\""
iex> inspect([0 | ~c"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 _. _ can only be used inside patterns to ignore values and cannot be used in expressions. Make sure you are inside a pattern or change it accordingly
Ещё один пример — карта в качестве шаблона выполняет сопоставление подмножества, но не после присваивания переменной:
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 в указанный нулево-базированный index в 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} для зарегистрированного имени на другом узле.
Дополнительную документацию см. в ! операторе в документации Erlang.
Встроено компилятором.
Примеры
iex> send(self(), :hello) :hello
sigil_C(term, modifiers)Source
Обрабатывает сигил ~C для списков символов.
Возвращает список символов без интерполяций и без управляющих последовательностей.
Список символов - это список целых чисел, где все целые числа являются допустимыми кодовыми точками. Три выражения ниже эквивалентны:
~C"foo\n" [?f, ?o, ?o, ?\\, ?n] [102, 111, 111, 92, 110]
На практике списки символов в основном используются в определенных сценариях, таких как взаимодействие со старыми библиотеками Erlang, которые не принимают двоичные данные в качестве аргументов.
Примеры
iex> ~C(foo)
~c"foo"
iex> ~C(f#{o}o)
~c"f\#{o}o"
iex> ~C(foo\n)
~c"foo\\n" sigil_c(term, modifiers)Source
Обрабатывает сигил ~c для списков символов.
Возвращает список символов, обрабатывая управляющие последовательности и заменяя интерполяции.
Список символов - это список целых чисел, где все целые числа являются допустимыми кодовыми точками. Три выражения ниже эквивалентны:
~c"foo" [?f, ?o, ?o] [102, 111, 111]
На практике списки символов в основном используются в определенных сценариях, таких как взаимодействие со старыми библиотеками Erlang, которые не принимают двоичные данные в качестве аргументов.
Примеры
iex> ~c(foo)
~c"foo"
iex> ~c(f#{:o}o)
~c"foo"
iex> ~c(f\#{:o}o)
~c"f\#{:o}o"
Список будет напечатан как сигил ~c только если все кодовые точки находятся в диапазоне ASCII:
iex> ~c"hełło" [104, 101, 322, 322, 111] iex> [104, 101, 108, 108, 111] ~c"hello"
См. Inspect.Opts для дополнительной информации.
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.
Примеры
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/" 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
[~c"foo", ~c"bar", ~c"baz"] spawn(fun)Source
@spec spawn((-> any())) :: 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, и возвращает ее идентификатор процесса.
Обычно разработчики не используют функции 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
Преобразует данное значение в список символов в соответствии с протоколом List.Chars.
Примеры
iex> to_charlist(:foo) ~c"foo"
to_string(term)Source
Преобразует аргумент в строку в соответствии с протоколом String.Chars.
Это функция, вызываемая при интерполяции строк.
Примеры
iex> to_string(:foo) "foo"
to_timeout(duration)Source
@spec to_timeout([component, ...] | timeout() | Duration.t()) :: timeout()
when component: [{unit, non_neg_integer()}, ...],
unit: :week | :day | :hour | :minute | :second | :millisecond Создаёт таймаут в миллисекундах из заданных компонентов, длительности или таймаута.
Эта функция полезна для создания таймаутов, используемых в функциях, которые ожидают значения timeout/0 (таких как Process.send_after/4 и многие другие).
Аргумент
Аргумент duration может быть значением Duration, значением timeout/0 или списком компонентов. Каждый из них описан ниже.
Передача значений Duration
Duration.t/0 структуры могут быть преобразованы в таймауты. Заданная длительность должна иметь поля year и month, установленные в значение 0, поскольку их нельзя надёжно преобразовать в миллисекунды (из-за переменного количества дней в месяце и году).
Микросекунды в длительностях преобразуются в миллисекунды (через System.convert_time_unit/3).
Передача компонентов
Аргумент duration также может быть списком ключевых слов, которые могут содержать следующие ключи, каждый из которых появляется не более одного раза со значением целого неотрицательного числа:
-
:week- количество недель (неделя всегда равна 7 дням) -
:day- количество дней (день всегда равен 24 часам) -
:hour- количество часов -
:minute- количество минут -
:second- количество секунд -
:millisecond- количество миллисекунд
Таймаут вычисляется как сумма компонентов, умноженных на соответствующий множитель.
Передача таймаутов
Вы также можете передать таймауты напрямую в эту функцию, т.е., миллисекунды или атом :infinity. В этом случае эта функция просто возвращает заданный аргумент.
Примеры
Со списком ключевых слов:
iex> to_timeout(hour: 1, minute: 30) 5400000
С длительностью:
iex> to_timeout(%Duration{hour: 1, minute: 30})
5400000
С таймаутом:
iex> to_timeout(5400000) 5400000 iex> to_timeout(:infinity) :infinity
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/2имеет небольшой контроль над тем, как вставляется код,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.
Поскольку use MyModule может генерировать любой код, разработчикам может быть трудно понять влияние use MyModule.
По этой причине, для предоставления рекомендаций и ясности, мы рекомендуем разработчикам включать блок предупреждения в их @moduledoc, который объясняет, как use MyModule влияет на их код. В качестве примера, документация GenServer описывает:
use GenServerКогда вы используете
use GenServer, модульGenServerустановит@behaviour GenServerи определит функциюchild_spec/1, так что ваш модуль может быть использован как дочерний элемент в дереве наблюдения.
Это обеспечивает краткий обзор того, как использование модуля влияет на код пользователя. Имейте в виду, что следует указывать только изменения в общедоступном API модуля. Например, если use MyModule устанавливает внутренний атрибут, называемый @_my_module_info, и этот атрибут никогда не предназначен для публичного использования, его не следует перечислять.
Для удобства, разметка для генерации блока предупреждения выше:
> #### `use GenServer` {: .info}
>
> When you `use GenServer`, the GenServer module will
> set `@behaviour GenServer` and define a `child_spec/1`
> function, so your module can be used as a child
> in a supervision tree. var!(var, context \\ nil)Source
Помечает, что заданная переменная не должна подвергаться гигиенизации.
Этот макрос ожидает переменную и обычно вызывается внутри quote/2 для того, чтобы отметить, что переменная не должна подвергаться гигиенизации. См. 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-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.17.2/Kernel.html