Spec-Zone.ru › Elixir 1.17

Исходный код Ядро

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.

END_OF_DOCUMENT_MARKER
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)

Удобный макрос, проверяющий, соответствует ли правая часть (выражение) левой части (шаблону).

END_OF_DOCUMENT_MARKER
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 для создания UTC DateTime.

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

Булевый оператор "или".

END_OF_DOCUMENT_MARKER

Операторы

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
END_OF_DOCUMENT_MARKER

левая и правая частиИсходный код

Оператор "и" строго для булевых значений.

Если 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
END_OF_DOCUMENT_MARKER

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.

Разрешено в тестах-ограничителях. Встраивается компилятором.

END_OF_DOCUMENT_MARKER

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 для получения дополнительной информации.

END_OF_DOCUMENT_MARKER

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:

  1. AST кода code
  2. AST кода options
  3. Окружение Macro.Env места вызова dbg/2

Функция отладки вызывается во время компиляции и должна также вернуть 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 для правил именования и аргументов по умолчанию.

END_OF_DOCUMENT_MARKER

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, возвращается nil

  • foo.bar - обращается к полю карты/структуры; в случае отсутствия поля, генерируется ошибка

Вот некоторые допустимые пути:

users["john"][:age]
users["john"].age
User.all()["john"].age
all_users()["john"].age

Вот некоторые недопустимые:

# Does a remote call after the initial value
users["john"].do_something(arg1, arg2)

# Does not access any key or field
users

get_and_update_in(data, keys, fun)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"
END_OF_DOCUMENT_MARKER

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])
END_OF_DOCUMENT_MARKER

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
END_OF_DOCUMENT_MARKER

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, этот оператор принимает любое выражение в качестве первого аргумента, а не только булевы значения.

Скачать версию ePub

Создано с помощью ExDoc (v0.34.1) для языка программирования Elixir

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.17.2/Kernel.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API