Spec-Zone.ru › Elixir 1.15

Ядро

Kernel является по умолчанию средой Elixir.

Она в основном состоит из:

  • базовых языковых примитивов, таких как арифметические операторы, создание процессов, обработка типов данных и другие
  • макросов для управления потоком и определения новых функций (модули, функции и т.п.)
  • проверок условий для расширения шаблонов сопоставления

Вы можете вызывать функции и макросы Kernel в любом месте кода Elixir без использования префикса Kernel., так как они все автоматически импортированы. Например, в IEx вы можете вызвать:

iex> is_number(13)
true

Если вы не хотите импортировать функцию или макрос из Kernel, используйте опцию :except и затем перечислите функцию/макрос по арности:

import Kernel, except: [if: 2, unless: 2]

См. Kernel.SpecialForms.import/2 для получения дополнительной информации об импорте.

Elixir также имеет специальные формы, которые всегда импортируются и не могут быть пропущены. Они описаны в Kernel.SpecialForms.

Стандартная библиотека

Kernel предоставляет базовые возможности, на которых построена стандартная библиотека Elixir. Рекомендуется изучить стандартную библиотеку для расширенного функционала. Вот основные группы модулей в стандартной библиотеке (этот список не является полным справочником, см. боковую панель документации для всех записей).

Встроенные типы

Следующие модули обрабатывают встроенные типы данных Elixir:

  • Atom - литеральные константы с именем (true, false, и nil являются атомами)
  • Float - числа с плавающей точкой
  • Function - ссылка на фрагмент кода, созданный с помощью специальной формы fn/1
  • Integer - целые числа (не дроби)
  • List - коллекции переменного числа элементов (связанные списки)
  • Map - коллекции пар ключ-значение
  • Process - лёгкие потоки выполнения
  • Port - механизмы взаимодействия с внешним миром
  • Tuple - коллекции фиксированного числа элементов

Существует два типа данных без сопровождающего модуля:

  • Битовая строка - последовательность битов, созданная с помощью Kernel.SpecialForms.<<>>/1. Когда количество битов делится на 8, они называются двоичными и могут быть обработаны модулем Erlang :binary
  • Ссылка - уникальное значение в системе выполнения, созданное с помощью make_ref/0

Типы данных

Elixir также предоставляет другие типы данных, построенные на основе перечисленных выше. Некоторые из них:

  • Date - структуры year-month-day в заданном календаре
  • DateTime - дата и время с часовым поясом в заданном календаре
  • Exception - данные, возникающие при ошибках и непредвиденных ситуациях
  • MapSet - неупорядоченные коллекции уникальных элементов
  • NaiveDateTime - дата и время без часового пояса в заданном календаре
  • Keyword - списки пар кортежей из двух элементов, часто представляющие необязательные значения
  • Range - включительные диапазоны между двумя целыми числами
  • Regex - регулярные выражения
  • String - двоичные данные в кодировке UTF-8, представляющие символы
  • Time - структуры hour:minute:second в заданном календаре
  • URI - представление URI, идентифицирующих ресурсы
  • Version - представление версий и требований

Модули системы

Модули, которые взаимодействуют с основной системой, например:

  • IO - обрабатывает ввод и вывод
  • File - взаимодействует с файловой системой
  • Path - манипулирует путями к файлам
  • System - считывает и записывает системную информацию

Протоколы

Протоколы добавляют полиморфную обработку в Elixir. Это контракты, реализуемые типами данных. См. Protocol для получения дополнительной информации о протоколах. Elixir предоставляет следующие протоколы в стандартной библиотеке:

  • Collectable - собирает данные в тип данных
  • Enumerable - обрабатывает коллекции в Elixir. Модуль Enum предоставляет жадные функции для работы с коллекциями, модуль Stream предоставляет ленивые функции
  • Inspect - преобразует типы данных в их представление в языке программирования
  • List.Chars - преобразует типы данных в их внешнее представление как charlists (не основанные на программировании)
  • String.Chars - преобразует типы данных в их внешнее представление как строки (не основанные на программировании)

Функциональность, основанная на процессах и ориентированная на приложения

Следующие модули строятся поверх процессов для обеспечения конкуретности, отказоустойчивости и др.

  • Agent - процесс, инкапсулирующий изменяемое состояние
  • Application - функции для запуска, остановки и конфигурации приложений
  • GenServer - универсальный API клиент-сервер
  • Registry - хранилище ключ-значение, основанное на процессах
  • Supervisor - процесс, ответственный за запуск, наблюдение и остановку других процессов
  • Task - процесс, выполняющий вычисления
  • Task.Supervisor - супервайзер для управления задачами исключительно

Дополнительные документы

Документация Elixir также включает дополнительные документы в разделе "Страницы". Это:

  • Совместимость и устаревшие функции - перечисляет совместимость между каждой версией Elixir и Erlang/OTP, схему выпуска; перечисляет все устаревшие функции, когда они устарели и альтернативы
  • Рекомендации по работе с библиотеками - общие рекомендации, антипаттерны и правила для разработчиков библиотек
  • Конвенции именования - соглашения об именовании для кода Elixir
  • Операторы - перечисляет все операторы Elixir и их приоритеты
  • Шаблоны и условия - введение в шаблоны, условия и расширения
  • Справочник синтаксиса - справочник синтаксиса языка
  • Типоспеки- типы и спецификации функций, включая список типов
  • Синтаксис Unicode - описывает поддержку Elixir для 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.

Структурное сравнение

Функции в этом модуле выполняют структурное сравнение. Это позволяет сравнивать разные типы данных с помощью операторов сравнения:

iex> 1 < :an_atom
true

Это возможно, чтобы разработчики 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. Чтобы выполнить семантические сравнения, соответствующие типы данных предоставляют функцию 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, length)

Извлекает часть бинарного значения, начиная с start длиной length. Бинарные значения индексируются с нуля.

bit_size(bitstring)

Возвращает целое число, которое является размером в битах bitstring.

byte_size(bitstring)

Возвращает количество байтов, необходимых для хранения bitstring.

ceil(number)

Возвращает наименьшее целое число, большее или равное number.

div(dividend, divisor)

Выполняет целочисленное деление.

elem(tuple, index)

Получает элемент по нулевому index индексу в tuple.

floor(number)

Возвращает наибольшее целое число, меньшее или равное number.

hd(list)

Возвращает начало списка. Вызывает ArgumentError если список пустой.

left in right

Оператор принадлежности.

is_atom(term)

Возвращает true если term является атомом; в противном случае возвращает false.

is_binary(term)

Возвращает true если term является бинарным значением; в противном случае возвращает false.

is_bitstring(term)

Возвращает true если term является битовой строкой (включая бинарные); в противном случае возвращает false.

is_boolean(term)

Возвращает true если term является атомом true или атомом false (т.е., булевым значением); в противном случае возвращает false.

is_exception(term)

Возвращает true, если term является исключением; в противном случае возвращает false.

is_exception(term, name)

Возвращает true, если term является исключением типа name; в противном случае возвращает false.

is_float(term)

Возвращает true если term является числом с плавающей точкой; в противном случае возвращает false.

is_function(term)

Возвращает true если term является функцией; в противном случае возвращает false.

is_function(term, arity)

Возвращает true если term является функцией, которая может быть применена с arity аргументами; в противном случае возвращает false.

is_integer(term)

Возвращает true если term является целым числом; в противном случае возвращает false.

is_list(term)

Возвращает true если term является списком с нулем или более элементами; в противном случае возвращает false.

is_map(term)

Возвращает true если term является картой; в противном случае возвращает false.

is_map_key(map, key)

Возвращает true если key является ключом в map; в противном случае возвращает false.

is_nil(term)

Возвращает true если term является nil, false в противном случае.

is_number(term)

Возвращает true если term является целым числом или числом с плавающей точкой; в противном случае возвращает false.

is_pid(term)

Возвращает true если term является PID (идентификатором процесса); в противном случае возвращает false.

is_port(term)

Возвращает true если term является идентификатором порта; в противном случае возвращает false.

is_reference(term)

Возвращает true если term является ссылкой; в противном случае возвращает false.

is_struct(term)

Возвращает true, если term является структурой; в противном случае возвращает false.

is_struct(term, name)

Возвращает true, если term является структурой типа name; в противном случае возвращает false.

is_tuple(term)

Возвращает true если term является кортежем; в противном случае возвращает false.

END_OF_DOCUMENT_MARKER
length(list)

Возвращает длину list.

map_size(map)

Возвращает размер карты.

node()

Возвращает атом, представляющий имя локального узла. Если узел не активен, возвращается :nonode@nohost.

node(arg)

Возвращает узел, где расположен заданный аргумент. Аргумент может быть PID, ссылкой или портом. Если локальный узел не активен, возвращается :nonode@nohost.

not value

Строго булевый оператор "not".

left or right

Строго булевый оператор "or".

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(data, keys)

Получает значение из вложенной структуры.

if(condition, clauses)

Предоставляет макрос if/2.

inspect(term, opts \\ [])

Проверяет данный аргумент согласно протоколу Inspect. Второй аргумент — список ключевых слов с параметрами для управления проверкой.

macro_exported?(module, macro, arity)

Возвращает true если module загружен и содержит публичный macro с заданной arity, в противном случае false.

make_ref()

Возвращает почти уникальную ссылку.

match?(pattern, expr)

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

max(first, second)

Возвращает наибольшее из двух заданных значений в соответствии со структурной компарацией.

min(first, second)

Возвращает наименьшее из двух заданных значений в соответствии со структурной компарацией.

pop_in(path)

Удаляет ключ из вложенной структуры по заданному path.

pop_in(data, keys)

Удаляет ключ из заданной вложенной структуры.

put_elem(tuple, index, value)

Размещает value по заданному нулевому index в tuple.

put_in(path, value)

Размещает значение в вложенной структуре по заданному 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_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.

unless(condition, clauses)

Предоставляет макрос unless.

update_in(path, fun)

Обновляет вложенную структуру с помощью заданной path.

update_in(data, keys, fun)

Обновляет ключ во вложенной структуре.

use(module, opts \\ [])

Использует данный модуль в текущем контексте.

var!(var, context \\ nil)

Помечает, что данная переменная не должна подвергаться гигиене.

left |> right

Оператор конвейера.

left || right

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

left * rightSource

@spec integer() * integer() :: integer()
@spec float() * float() :: float()
@spec integer() * float() :: float()
@spec float() * integer() :: float()

Оператор арифметического умножения.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> 1 * 2
2

+valueSource

@spec +integer() :: integer()
@spec +float() :: float()

Унарный оператор арифметического положительного знака.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> +1
1

left + rightSource

@spec integer() + integer() :: integer()
@spec float() + float() :: float()
@spec integer() + float() :: float()
@spec float() + integer() :: float()

Оператор арифметического сложения.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> 1 + 2
3

-valueSource

@spec -0 :: 0
@spec -pos_integer() :: neg_integer()
@spec -neg_integer() :: pos_integer()
@spec -float() :: float()

Унарный оператор арифметического отрицательного знака.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> -2
-2

left - rightSource

@spec integer() - integer() :: integer()
@spec float() - float() :: float()
@spec integer() - float() :: float()
@spec float() - integer() :: float()

Оператор арифметического вычитания.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> 1 - 2
-1

left / rightSource

@spec number() / number() :: float()

Оператор арифметического деления.

Результат всегда является числом с плавающей точкой. Используйте div/2 и rem/2, если вам нужно целочисленное деление или остаток.

Вызывает ArithmeticError, если right равно 0 или 0.0.

Допускается в тестах guard. Встраивается компилятором.

Примеры

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 могут сравниваться друг с другом. См. раздел "Структурное сравнение" для получения дополнительной информации.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> 1 != 2
true

iex> 1 != 1.0
false

left !== rightSource

@spec term() !== term() :: boolean()

Оператор строгого неравенства.

Возвращает true, если два члена не точно равны. См. ===/2 для определения того, что считается "точно равным".

Это выполняет структурное сравнение, где все члены Elixir могут сравниваться друг с другом. См. раздел "Структурное сравнение" для получения дополнительной информации.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> 1 !== 2
true

iex> 1 !== 1.0
true

left < rightSource

@spec term() < term() :: boolean()

Оператор "меньше чем".

Возвращает true, если left меньше чем right.

Это выполняет структурное сравнение, где все члены Elixir могут сравниваться друг с другом. См. раздел "Структурное сравнение" для получения дополнительной информации.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> 1 < 2
true

left <= rightSource

@spec term() <= term() :: boolean()

Оператор "меньше чем или равно".

Возвращает true, если left меньше чем или равно right.

Это выполняет структурное сравнение, где все члены Elixir могут сравниваться друг с другом. См. раздел "Структурное сравнение" для получения дополнительной информации.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> 1 <= 2
true

left == rightSource

@spec term() == term() :: boolean()

Оператор равенства. Возвращает true, если два члена равны.

Этот оператор считает 1 и 1.0 равными. Для более строгой семантики используйте ===/2.

Это выполняет структурное сравнение, где все члены Elixir могут сравниваться друг с другом. См. раздел "Структурное сравнение" для получения дополнительной информации.

Допускается в тестах guard. Встраивается компилятором.

Примеры

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 могут сравниваться друг с другом. См. раздел "Структурное сравнение" для получения дополнительной информации.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> 1 === 2
false

iex> 1 === 1.0
false

left > rightSource

@spec term() > term() :: boolean()

Оператор "больше чем".

Возвращает true, если left больше чем right.

Это выполняет структурное сравнение, где все члены Elixir могут сравниваться друг с другом. См. раздел "Структурное сравнение" для получения дополнительной информации.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> 1 > 2
false

left >= rightSource

@spec term() >= term() :: boolean()

Оператор "больше чем или равно".

Возвращает true, если left больше чем или равно right.

Это выполняет структурное сравнение, где все члены Elixir могут сравниваться друг с другом. См. раздел "Структурное сравнение" для получения дополнительной информации.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> 1 >= 2
false

abs(number)Source

@spec abs(number()) :: number()

Возвращает целое число или число с плавающей точкой, которое является арифметическим абсолютным значением number.

Допускается в тестах guard. Встраивается компилятором.

Примеры

iex> abs(-3.33)
3.33

iex> abs(-3)
3

left and rightSource

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

Если 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(binary, start, length)Source

@spec binary_part(binary(), non_neg_integer(), integer()) :: binary()

Извлекает часть бинарного объекта, начиная с start с длиной length . Бинарные объекты нумеруются с нуля.

Если start или length каким-либо образом ссылаются за пределы бинарного объекта, генерируется исключение ArgumentError.

Разрешено в тестах стражей. Встроенный компилятором.

Примеры

iex> binary_part("foo", 1, 2)
"oo"

Отрицательная length может использоваться для извлечения байтов, предшествующих байту по индексу start:

iex> binary_part("Hello", 5, -3)
"llo"

Исключение ArgumentError генерируется, если длина выходит за пределы бинарного объекта:

binary_part("Hello", 0, 10)
** (ArgumentError) argument error

bit_size(bitstring)Source

@spec bit_size(bitstring()) :: non_neg_integer()

Возвращает целое число, представляющее размер bitstring в битах.

Разрешено в тестах стражей. Встроенный компилятором.

Примеры

iex> bit_size(<<433::16, 3::3>>)
19

iex> bit_size(<<1, 2, 3>>)
24

byte_size(bitstring)Source

@spec byte_size(bitstring()) :: non_neg_integer()

Возвращает количество байтов, необходимое для хранения bitstring.

То есть, если количество битов в bitstring не делится на 8, полученное количество байтов будет округлено вверх (до ближайшего большего). Эта операция выполняется за постоянное время.

Разрешено в тестах стражей. Встроенный компилятором.

Примеры

iex> byte_size(<<433::16, 3::3>>)
3

iex> byte_size(<<1, 2, 3>>)
3

ceil(number)Source

@spec ceil(number()) :: integer()

Возвращает наименьшее целое число, большее или равное number.

Если требуется выполнить операцию ceil для других десятичных знаков, используйте Float.ceil/2.

Разрешено в тестах стражей. Встроенный компилятором.

Примеры

iex> ceil(10)
10

iex> ceil(10.1)
11

iex> ceil(-10.1)
-10

div(dividend, divisor)Source

@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(tuple, index)Source

@spec elem(tuple(), non_neg_integer()) :: term()

Получает элемент по нулевому индексу index в tuple.

Генерирует исключение ArgumentError, когда индекс отрицательный или выходит за пределы кортежа.

Разрешено в тестах стражей. Встроенный компилятором.

Примеры

tuple = {:foo, :bar, 3}
elem(tuple, 1)
#=> :bar

elem({}, 0)
** (ArgumentError) argument error

elem({:foo, :bar}, 2)
** (ArgumentError) argument error

floor(number)Source

@spec floor(number()) :: integer()

Возвращает наибольшее целое число, меньшее или равное number.

Если требуется выполнить операцию floor для других десятичных знаков, используйте Float.floor/2.

Разрешено в тестах стражей. Встроенный компилятором.

Примеры

iex> floor(10)
10

iex> floor(9.7)
9

iex> floor(-9.7)
-10

hd(list)Source

@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

left in rightSource

Оператор принадлежности.

Проверяет, является ли элемент слева элементом коллекции справа.

Примеры

iex> x = 1
iex> x in [1, 2, 3]
true

Этот оператор (который является макросом) просто преобразуется в вызов Enum.member?/2. Приведенный выше пример преобразуется в:

Enum.member?([1, 2, 3], x)

Elixir также поддерживает left not in right, что эквивалентно not(left in right):

iex> x = 1
iex> x not in [1, 2, 3]
false

Стражи

Оператор in/2 (а также not in) может использоваться в условиях стражей, если правая часть — это диапазон или список.

Если правая часть — это список, Elixir преобразует оператор в допустимое выражение стражи, которое должно проверить каждое значение. Например:

when x in [1, 2, 3]

преобразуется в:

when x === 1 or x === 2 or x === 3

Однако, это конструкция будет неэффективной для больших списков. В таких случаях лучше отказаться от использования стражей и использовать более подходящую структуру данных, такую как MapSet.

Если правая часть — диапазон, будет выполнена более эффективная проверка сравнения. Например:

when x in 1..1000

примерно преобразуется в:

when x >= 1 and x <= 1000

Учёт AST

left not in right парсится компилятором в AST:

{:not, _, [{:in, _, [left, right]}]}

Это тот же AST, что и not(left in right).

Кроме того, Macro.to_string/2 и Code.format_string!/2 преобразуют все вхождения этого AST в left not in right.

is_atom(term)Source

@spec is_atom(term()) :: boolean()

Возвращает true если term является атомом; в противном случае возвращает false.

Разрешено в тестах стражей. Встроенный компилятором.

Примеры

iex> is_atom(false)
true

iex> is_atom(:name)
true

iex> is_atom(AnAtom)
true

iex> is_atom("true")
false

is_binary(term)Source

@spec is_binary(term()) :: boolean()

Возвращает true если term является бинарным объектом; в противном случае возвращает false.

Бинарный объект всегда содержит целое число байтов.

Разрешено в тестах стражей. Встроенный компилятором.

Примеры

iex> is_binary("foo")
true
iex> is_binary(<<1::3>>)
false

is_bitstring(term)Source

@spec is_bitstring(term()) :: boolean()

Возвращает true если term является битовой строкой (включая бинарный объект); в противном случае возвращает false.

Разрешено в тестах стражей. Встроенный компилятором.

Примеры

iex> is_bitstring("foo")
true
iex> is_bitstring(<<1::3>>)
true
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.

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

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_number(term)Source

@spec is_number(term()) :: boolean()

Возвращает true, если term является либо целым числом, либо числом с плавающей запятой; в противном случае возвращает false.

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

is_pid(term)Source

@spec is_pid(term()) :: boolean()

Возвращает true, если term является идентификатором процесса (PID); в противном случае возвращает false.

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

is_port(term)Source

@spec is_port(term()) :: boolean()

Возвращает true, если term является идентификатором порта; в противном случае возвращает false.

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

is_reference(term)Source

@spec is_reference(term()) :: boolean()

Возвращает true, если term является ссылкой; в противном случае возвращает false.

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

is_struct(term)Source

Возвращает true, если term является структурой; в противном случае возвращает false.

Разрешено в тестах стражей.

Примеры

iex> is_struct(URI.parse("/"))
true

iex> is_struct(%{})
false

is_struct(term, name)Source

Возвращает true, если term является структурой типа name; в противном случае возвращает false.

is_struct/2 не проверяет, существует ли name и является ли она валидной структурой. Если вам нужны такие проверки, вы должны использовать сопоставление с образцом на структуре, например, match?(%URI{}, arg).

Разрешено в тестах стражей.

Примеры

iex> is_struct(URI.parse("/"), URI)
true

iex> is_struct(URI.parse("/"), Macro.Env)
false

is_tuple(term)Source

@spec is_tuple(term()) :: boolean()

Возвращает true, если term является кортежем; в противном случае возвращает false.

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

length(list)Source

@spec length(list()) :: non_neg_integer()

Возвращает длину list.

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

Примеры

iex> length([1, 2, 3, 4, 5, 6, 7, 8, 9])
9

map_size(map)Source

@spec map_size(map()) :: non_neg_integer()

Возвращает размер карты.

Размер карты — это количество пар ключ-значение, содержащихся в карте.

Эта операция выполняется за константное время.

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

Примеры

iex> map_size(%{a: "foo", b: "bar"})
2
END_OF_DOCUMENT_MARKER

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

Оператор "not" строго булевого типа.

value должен быть булевым значением; если нет, генерируется исключение ArgumentError.

Допускается в тестах стражей. Встраивается компилятором.

Примеры

iex> not false
true

left or rightSource

Оператор "or" строго булевого типа.

Если 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 list() ++ term() :: maybe_improper_list()

Оператор конкатенации списков. Объединяет правильный список и элемент, возвращая список.

Сложность операции a ++ b пропорциональна length(a), поэтому следует избегать многократного добавления в списки произвольной длины, например, list ++ [element]. Вместо этого рассмотрите добавление в начало с помощью [element | rest] и последующего обращения списка.

Если операнд right не является правильным списком, возвращается неправильный список. Если операнд left не является правильным списком, генерируется исключение ArgumentError.

Встроен в компилятор.

Примеры

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]

Оператор ++/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.

END_OF_DOCUMENT_MARKER

@exprSource

Унарный оператор атрибута модуля.

Читает и записывает атрибуты в текущем модуле.

Классический пример атрибутов — аннотирование модуля, реализующего поведение OTP, например GenServer:

defmodule MyServer do
  @behaviour GenServer
  # ... callbacks ...
end

По умолчанию Elixir поддерживает все атрибуты модулей, поддерживаемые Erlang, но также можно использовать пользовательские атрибуты:

defmodule MyServer do
  @my_data 13
  IO.inspect(@my_data)
  #=> 13
end

В отличие от Erlang, такие атрибуты по умолчанию не хранятся в модуле, так как в Elixir часто используются пользовательские атрибуты для хранения временных данных, доступных на этапе компиляции. Пользовательские атрибуты можно настроить, чтобы они вели себя более похоже на Erlang, используя Module.register_attribute/3.

Префикс атрибутов модуля

Библиотеки и фреймворки должны использовать префикс подчеркивания для атрибутов модуля, предназначенных для внутреннего использования, например @_my_data, чтобы средства автодополнения кода не отображали их в подсказках и запросах.

Наконец, обратите внимание, что атрибуты также можно читать внутри функций:

defmodule MyServer do
  @my_data 11
  def first_data, do: @my_data
  @my_data 13
  def second_data, do: @my_data
end

MyServer.first_data()
#=> 11

MyServer.second_data()
#=> 13

Важно отметить, что чтение атрибута создаёт моментальную копию его текущего значения. Другими словами, значение считывается во время компиляции, а не во время выполнения. Обратитесь к модулю Module для получения других функций управления атрибутами модулей.

Внимание! Несколько ссылок на один и тот же атрибут

Как упоминалось выше, каждый раз при чтении атрибута модуля делается моментальная копия его текущего значения. Поэтому, если вы храните большие значения в атрибутах модуля (например, встраиваете внешние файлы в атрибуты модуля), следует избегать многократных ссылок на один и тот же атрибут. Например, не делайте так:

@files %{
  example1: File.read!("lib/example1.data"),
  example2: File.read!("lib/example2.data")
}

def example1, do: @files[:example1]
def example2, do: @files[:example2]

В приведенном примере каждая ссылка на @files может привести к полной и независимой копии всего атрибута модуля @files. Вместо этого сделайте ссылку на атрибут модуля один раз в частной функции:

@files %{
  example1: File.read!("lib/example1.data"),
  example2: File.read!("lib/example2.data")
}

defp files(), do: @files
def example1, do: files()[:example1]
def example2, do: files()[:example2]

Внимание! Зависимости от компиляции

Помните, что ссылки на другие модули, даже в атрибутах модулей, создают зависимости от компиляции к этим модулям.

Например, рассмотрите этот распространенный шаблон:

@values [:foo, :bar, :baz]

def handle_arg(arg) when arg in @values do
  ...
end

Хотя приведенный выше пример корректен, представьте, что у вас есть фактические имена модулей в атрибуте модуля, как в этом примере:

@values [Foo, Bar, Baz]

def handle_arg(arg) when arg in @values do
  ...
end

Приведенный выше код определит зависимость от компиляции от модулей Foo, Bar, и Baz, таким образом, что при изменении любого из них текущий модуль должен будет перекомпилироваться. В таких случаях может быть предпочтительнее вообще отказаться от использования атрибута модуля:

def handle_arg(arg) when arg in [Foo, Bar, Baz] do
  ...
end

alias!(alias)Source

При использовании внутри цитирования указывает, что данный псевдоним не должен подвергаться гигиене. Это означает, что псевдоним будет расширен при расширении макроса.

См. Kernel.SpecialForms.quote/2 для получения дополнительной информации.

apply(fun, args)Source

@spec apply((... -> any()), [any()]) :: any()

Вызывает данную анонимную функцию fun со списком аргументов args.

Если количество аргументов известно на этапе компиляции, предпочтительнее использовать fun.(arg_1, arg_2, ..., arg_n), так как оно понятнее, чем apply(fun, [arg_1, arg_2, ..., arg_n]).

Встраивается компилятором.

Примеры

iex> apply(fn x -> x * 2 end, [2])
4

apply(module, function_name, args)Source

@spec apply(module(), function_name :: atom(), [any()]) :: any()

Вызывает указанную функцию из module со списком аргументов args.

apply/3 используется для вызова функций, где модуль, имя функции или аргументы определяются динамически во время выполнения. По этой причине вы не можете вызывать макросы с помощью apply/3, только функции.

Если количество аргументов и имя функции известны на этапе компиляции, предпочтительнее использовать module.function(arg_1, arg_2, ..., arg_n), так как оно понятнее, чем apply(module, :function, [arg_1, arg_2, ..., arg_n]).

apply/3 не может использоваться для вызова закрытых функций.

Встраивается компилятором.

Примеры

iex> apply(Enum, :reverse, [[1, 2, 3]])
[3, 2, 1]

binary_slice(binary, range)Source

Возвращает двоичную строку от смещения, заданного началом диапазона, до смещения, заданного концом диапазона.

Если начало или конец диапазона отрицательны, они преобразуются в положительные индексы на основе размера двоичной строки. Например, -1 означает последний байт двоичной строки.

Это аналогично binary_part/3, за исключением того, что оно работает с диапазонами и его нельзя использовать в защитах.

Функция работает с байтами. Для операции среза, учитывающей символы, см. String.slice/2.

Примеры

iex> binary_slice("elixir", 0..5)
"elixir"
iex> binary_slice("elixir", 1..3)
"lix"
iex> binary_slice("elixir", 1..10)
"lixir"

iex> binary_slice("elixir", -4..-1)
"ixir"
iex> binary_slice("elixir", -4..6)
"ixir"
iex> binary_slice("elixir", -10..10)
"elixir"

Для диапазонов, где start > stop, необходимо явно указать их как возрастающие:

iex> binary_slice("elixir", 2..-1//1)
"ixir"
iex> binary_slice("elixir", 1..-2//1)
"lixi"

Можно использовать ../0 как сокращение для 0..-1//1, что возвращает всю двоичную строку как есть:

iex> binary_slice("elixir", ..)
"elixir"

Шаг может быть любым положительным числом. Например, чтобы получить каждый второй символ двоичной строки:

iex> binary_slice("elixir", 0..-1//2)
"eii"

Если первая позиция находится после конца строки или после последней позиции диапазона, возвращается пустая строка:

iex> binary_slice("elixir", 10..3//1)
""
iex> binary_slice("elixir", -10..-7)
""
iex> binary_slice("a", 1..1500)
""

binary_slice(binary, start, size)Source

Возвращает двоичную строку, начинающуюся со смещения start и заданного size.

Это аналогично binary_part/3, за исключением того, что если start + size больше размера двоичной строки, она автоматически усекается до размера двоичной строки вместо вывода исключения. В отличие от binary_part/3, эта функция недопустима в защитах.

Функция работает с байтами. Для операции среза, учитывающей символы, см. String.slice/3.

Примеры

iex> binary_slice("elixir", 0, 6)
"elixir"
iex> binary_slice("elixir", 0, 5)
"elixi"
iex> binary_slice("elixir", 1, 4)
"lixi"
iex> binary_slice("elixir", 0, 10)
"elixir"

Если start отрицательное, оно нормализуется относительно размера двоичной строки и приводится к 0:

iex> binary_slice("elixir", -3, 10)
"xir"
iex> binary_slice("elixir", -10, 10)
"elixir"

Если size равно нулю, возвращается пустая двоичная строка:

iex> binary_slice("elixir", 1, 0)
""

Если start больше или равно размеру двоичной строки, возвращается пустая двоичная строка:

iex> binary_slice("elixir", 10, 10)
""

binding(context \\ nil)Source

Возвращает связывание для данного контекста в виде списка ключевых слов.

В возвращаемом результате ключи — имена переменных, а значения — соответствующие значения переменных.

Если заданный context равен nil (по умолчанию), возвращается связывание для текущего контекста.

Примеры

iex> x = 1
iex> binding()
[x: 1]
iex> x = 2
iex> binding()
[x: 2]

iex> binding(:foo)
[]
iex> var!(x, :foo) = 1
1
iex> binding(:foo)
[x: 1]

dbg(code \\ quote do binding() end, options \\ [])Source

Отлаживает заданный code.

dbg/2 может использоваться для отладки заданного code с помощью настраиваемой функции отладки. Возвращает результат заданного кода.

Примеры

Рассмотрим этот вызов dbg/2:

dbg(Atom.to_string(:debugging))
#=> "debugging"

Возвращает строку "debugging", которая является результатом вызова Atom.to_string/1. Кроме того, вышеприведённый вызов выводит:

[my_file.ex:10: MyMod.my_fun/0]
Atom.to_string(:debugging) #=> "debugging"

По умолчанию функция отладки печатает дополнительную отладочную информацию при работе с конвейерами. Она печатает значения на каждом «шаге» конвейера.

"Elixir is cool!"
|> String.trim_trailing("!")
|> String.split()
|> List.first()
|> dbg()
#=> "Elixir"

Приведённый выше код выводит:

[my_file.ex:10: MyMod.my_fun/0]
"Elixir is cool!" #=> "Elixir is cool!"
|> String.trim_trailing("!") #=> "Elixir is cool"
|> String.split() #=> ["Elixir", "is", "cool"]
|> List.first() #=> "Elixir"

Без аргументов dbg() отлаживает информацию о текущей области видимости. См. binding/1.

dbg в IEx

Вы можете включить IEx для замены dbg на его бэкенд IEx.pry/0 вызовом:

$ iex --dbg pry

В таких случаях dbg запустит сеанс pry, где вы можете взаимодействовать с импортами, псевдонимами и переменными текущей среды в месте вызова dbg.

Если вы вызываете dbg в конце конвейера (используя |> ) в IEx, вы сможете проходить по каждому шагу конвейера по одному, вводя «next» (или «n»).

Обратите внимание dbg поддерживает пошаговое выполнение только для конвейеров (то есть, он может выполнить только тот код, который видит). Для общего пошагового выполнения вы можете установить точки останова с помощью IEx.break!/4.

Для получения дополнительной информации см. документацию IEx по адресу IEx documentation.

Настройка функции отладки

Одно из преимуществ 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:

  • должны быть атомами
  • могут быть указаны несколько раз
  • упорядочены, как указано разработчиком

Имена функций и переменных

Имена функций и переменных имеют следующий синтаксис: строчная буква ASCII или подчёркивание, за которыми следует любое количество строчных или прописных букв ASCII, цифр или подчёркиваний. Дополнительно они могут заканчиваться знаком восклицания или вопросительным знаком.

Для переменных любой идентификатор, начинающийся с подчёркивания, должен указывать на неиспользуемую переменную. Например:

def foo(bar) do
  []
end
#=> warning: variable bar is unused

def foo(_bar) do
  []
end
#=> no warning

def foo(_bar) do
  _bar
end
#=> warning: the underscored variable "_bar" is used after being set

rescue/catch/after/else

Тела функций поддерживают rescue, catch, after, и else как и Kernel.SpecialForms.try/1 (известный как «явный try»). Например, следующие две функции эквивалентны:

def convert(number) do
  try do
    String.to_integer(number)
  rescue
    e in ArgumentError -> {:error, e.message}
  end
end

def convert(number) do
  String.to_integer(number)
rescue
  e in ArgumentError -> {:error, e.message}
end

defdelegate(funs, opts)Source

Определяет функцию, которая делегирует выполнение другой модули.

Функции, определённые с помощью defdelegate/2, являются публичными и могут быть вызваны извне модуля, в котором они определены, как если бы они были определены с помощью def/2. Поэтому defdelegate/2 относится к расширению публичного API текущего модуля. Если вы хотите вызвать функцию, определённую в другом модуле, не используя его полное имя модуля, используйте alias/2 для сокращения имени модуля или используйте import/2, чтобы вы могли вызвать функцию без имени модуля.

Делегирование работает только с функциями; делегирование макросов не поддерживается.

См. def/2 для правил именования и аргументов по умолчанию.

Параметры

  • :to - модуль, которому будет делегировано выполнение.

  • :as - функция, которая будет вызвана на целевом модуле, указанном в :to. Этот параметр необязателен и по умолчанию равен имени делегируемой функции (funs).

Примеры

defmodule MyList do
  defdelegate reverse(list), to: Enum
  defdelegate other_reverse(list), to: Enum, as: :reverse
end

MyList.reverse([1, 2, 3])
#=> [3, 2, 1]

MyList.other_reverse([1, 2, 3])
#=> [3, 2, 1]

defexception(fields)Source

Определяет исключение.

Исключения являются структурами, поддерживаемыми модулем, который реализует поведение Exception. Поведение Exception требует реализации двух функций:

  • exception/1 - получает аргументы, переданные в raise/2, и возвращает структуру исключения. Реализация по умолчанию принимает либо набор ключевых аргументов, который сливается в структуру, либо строку, которая используется в качестве сообщения исключения.

  • message/1 - получает структуру исключения и должна вернуть её сообщение. Чаще всего исключения имеют поле message, к которому по умолчанию обращается эта функция. Однако, если исключение не имеет поля message, эта функция должна быть реализована явно.

Поскольку исключения являются структурами, API, поддерживаемый defstruct/1, также доступен в defexception/1.

Выбрасывание исключений

Наиболее распространённый способ выброса исключения — использование raise/2:

defmodule MyAppError do
  defexception [:message]
end

value = [:hello]

raise MyAppError,
  message: "did not get what was expected, got: #{inspect(value)}"

Во многих случаях удобнее передать ожидаемое значение в raise/2 и сгенерировать сообщение в обратном вызове Exception.exception/1:

defmodule MyAppError do
  defexception [:message]

  @impl true
  def exception(value) do
    msg = "did not get what was expected, got: #{inspect(value)}"
    %MyAppError{message: msg}
  end
end

raise MyAppError, value

Приведённый выше пример демонстрирует предпочтительный способ настройки сообщений об исключениях.

END_OF_DOCUMENT_MARKER

defguard(guard)Source

@spec defguard(Macro.t()) :: Macro.t()

Генерирует макрос, подходящий для использования в выражениях фильтров.

Вызывает ошибку во время компиляции, если определение использует выражения, которые недопустимы в фильтрах, а в противном случае создает макрос, который можно использовать как внутри, так и вне фильтров.

Обратите внимание на соглашение в Elixir: все фильтры, возвращающие булево значение, должны предваряться префиксом is_, например, is_list/1. Однако, если функция/макрос возвращает булево значение, но не допускается в фильтрах, он не должен иметь префикса и заканчиваться вопросительным знаком, например, Keyword.keyword?/1.

Пример

defmodule Integer.Guards do
  defguard is_even(value) when is_integer(value) and rem(value, 2) == 0
end

defmodule Collatz do
  @moduledoc "Tools for working with the Collatz sequence."
  import Integer.Guards

  @doc "Determines the number of steps `n` takes to reach `1`."
  # If this function never converges, please let me know what `n` you used.
  def converge(n) when n > 0, do: step(n, 0)

  defp step(1, step_count) do
    step_count
  end

  defp step(n, step_count) when is_even(n) do
    step(div(n, 2), step_count + 1)
  end

  defp step(n, step_count) do
    step(3 * n + 1, step_count + 1)
  end
end

defguardp(guard)Source

@spec defguardp(Macro.t()) :: Macro.t()

Генерирует частный макрос, подходящий для использования в выражениях фильтров.

Вызывает ошибку во время компиляции, если определение использует выражения, которые недопустимы в фильтрах, а в противном случае создает частный макрос, который можно использовать как внутри, так и вне фильтров в текущем модуле.

Аналогично defmacrop/2, defguardp/1 должен быть определен до его использования в текущем модуле.

defimpl(name, opts, do_block \\ [])Source

Определяет реализацию для данного протокола.

См. модуль Protocol для получения дополнительной информации.

defmacro(call, expr \\ nil)Source

Определяет публичный макрос с заданным именем и телом.

Макросы должны быть определены перед их использованием.

См. def/2 для правил именования и аргументов по умолчанию.

Примеры

defmodule MyLogic do
  defmacro unless(expr, opts) do
    quote do
      if !unquote(expr), unquote(opts)
    end
  end
end

require MyLogic

MyLogic.unless false do
  IO.puts("It works")
end

defmacrop(call, expr \\ nil)Source

Определяет частный макрос с заданным именем и телом.

Частные макросы доступны только из того же модуля, в котором они определены.

Частные макросы должны быть определены перед их использованием.

См. defmacro/2 для получения дополнительной информации и def/2 для правил именования и аргументов по умолчанию.

defmodule(alias, do_block)Source

Определяет модуль с заданным именем и содержимым.

Этот макрос определяет модуль с заданным alias в качестве имени и с заданным содержимым. Он возвращает кортеж из четырёх элементов:

  • :module
  • имя модуля
  • бинарное содержимое модуля
  • результат вычисления блока содержимого

Примеры

defmodule Number do
  def one, do: 1
  def two, do: 2
end
#=> {:module, Number, <<70, 79, 82, ...>>, {:two, 0}}

Number.one()
#=> 1

Number.two()
#=> 2

Вложенность

Вложенность модуля внутри другого модуля влияет на имя вложенного модуля:

defmodule Foo do
  defmodule Bar do
  end
end

В примере выше создаются два модуля - Foo и Foo.Bar. При вложенности Elixir автоматически создаёт псевдоним для внутреннего модуля, позволяя обратиться ко второму модулю Foo.Bar как к Bar в той же лексической области, где он определен (в модуле Foo). Это происходит только если вложенный модуль определяется через псевдоним.

Если модуль Foo.Bar перемещен в другое место, ссылки на Bar в модуле Foo нужно обновить на полное имя (Foo.Bar) или установить псевдоним явно в модуле Foo с помощью Kernel.SpecialForms.alias/2.

defmodule Foo.Bar do
  # code
end

defmodule Foo do
  alias Foo.Bar
  # code here can refer to "Foo.Bar" as just "Bar"
end

Динамические имена

Имена модулей в Elixir могут быть сгенерированы динамически. Это очень полезно при работе с макросами. Например, можно написать:

defmodule String.to_atom("Foo#{1}") do
  # contents ...
end

Elixir примет любое имя модуля, если выражение, переданное в качестве первого аргумента к defmodule/2, вычисляется в атом. Обратите внимание, что при использовании динамического имени Elixir не будет вкладывать имя в текущий модуль и автоматически устанавливать псевдоним.

Зарезервированные имена модулей

Если вы попытаетесь определить модуль, который уже существует, вы получите предупреждение о том, что модуль был переопределён.

Существуют некоторые модули, которые Elixir пока не реализует, но возможно будут реализованы в будущем. Эти модули зарезервированы, и их определение приведёт к ошибке компиляции:

defmodule Any do
  # code
end
** (CompileError) iex:1: module Any is reserved and cannot be defined

Elixir зарезервировал следующие имена модулей: Elixir, Any, BitString, PID, и Reference.

defoverridable(keywords_or_behaviour)Source

Делает заданные определения в текущем модуле переопределяемыми.

Если пользователь определяет новую функцию или макрос с тем же именем и арностью, то переопределяемые определения отбрасываются. В противном случае используются исходные определения.

Возможна ситуация, когда переопределённое определение имеет другой уровень видимости, чем исходное: публичная функция может быть переопределена частной функцией и наоборот.

Макросы не могут быть переопределены как функции, и наоборот.

Пример

defmodule DefaultMod do
  defmacro __using__(_opts) do
    quote do
      def test(x, y) do
        x + y
      end

      defoverridable test: 2
    end
  end
end

defmodule ChildMod do
  use DefaultMod

  def test(x, y) do
    x * y + super(x, y)
  end
end

Как видно из примера выше, super можно использовать для вызова реализации по умолчанию.

Предупреждение

Используйте defoverridable с осторожностью. Если вам нужно определить несколько модулей с одинаковым поведением, может быть лучше перенести реализацию по умолчанию к вызывающему модулю и проверить, существует ли обратный вызов с помощью Code.ensure_loaded?/1 и function_exported?/3.

Например, в примере выше, представьте, что есть модуль, который вызывает функцию test/2. Этот модуль может быть определен следующим образом:

defmodule CallsTest do
  def receives_module_and_calls_test(module, x, y) do
    if Code.ensure_loaded?(module) and function_exported?(module, :test, 2) do
      module.test(x, y)
    else
      x + y
    end
  end
end

Пример с поведением

Вы также можете передать поведение в defoverridable и это пометит все обратные вызовы в поведении как переопределяемые:

defmodule Behaviour do
  @callback test(number(), number()) :: number()
end

defmodule DefaultMod do
  defmacro __using__(_opts) do
    quote do
      @behaviour Behaviour

      def test(x, y) do
        x + y
      end

      defoverridable Behaviour
    end
  end
end

defmodule ChildMod do
  use DefaultMod

  def test(x, y) do
    x * y + super(x, y)
  end
end

defp(call, expr \\ nil)Source

Определяет частную функцию с заданным именем и телом.

Частные функции доступны только изнутри модуля, в котором они определены. Попытка доступа к частной функции извне модуля, в котором она определена, приводит к исключению UndefinedFunctionError.

См. def/2 для получения дополнительной информации.

Примеры

defmodule Foo do
  def bar do
    sum(1, 2)
  end

  defp sum(a, b), do: a + b
end

Foo.bar()
#=> 3

Foo.sum(1, 2)
** (UndefinedFunctionError) undefined function Foo.sum/2

defprotocol(name, do_block)Source

Определяет протокол.

См. модуль Protocol для получения дополнительной информации.

defstruct(fields)Source

Определяет структуру.

Структура — это помеченная карта, которая позволяет разработчикам предоставлять значения по умолчанию для ключей, метки для использования в полиморфных диспатчах и утверждениях на этапе компиляции. Дополнительную информацию о структурах можно найти на странице Kernel.SpecialForms.%/2.

Определение структуры возможно только в пределах одного модуля, так как структура связана с самим модулем. Вызов defstruct/1 также определяет функцию __struct__/0, которая возвращает саму структуру.

Примеры

defmodule User do
  defstruct name: nil, age: nil
end

Поля структуры оцениваются на этапе компиляции, что позволяет им быть динамическими. В примере ниже 10 + 11 оценивается на этапе компиляции, и поле age хранится со значением 21:

defmodule User do
  defstruct name: nil, age: 10 + 11
end

Аргумент fields обычно представляет собой список ключевых слов со именами полей в качестве атомарных ключей и значениями по умолчанию в качестве соответствующих значений. defstruct/1 также поддерживает список атомов в качестве аргумента: в этом случае атомы в списке будут использоваться в качестве имён полей структуры, и все они будут иметь значение по умолчанию nil.

defmodule Post do
  defstruct [:title, :content, :author]
end

Добавьте документацию к структуре с помощью атрибута @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. Если реализация 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 является пустым, возвращается 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
END_OF_DOCUMENT_MARKER

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. Если любое из промежуточных значений равно nil, будет вызвано исключение:

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users, ["jane", :age], &{&1, &1 + 1})
** (ArgumentError) could not put/update key :age on a nil value

Функции в качестве ключей

Если ключ — функция, функция будет вызвана с тремя аргументами:

  • операция (:get_and_update)
  • данные для доступа
  • функция, которая будет вызвана далее

Это означает, что get_and_update_in/3 можно расширить для предоставления настраиваемых поисков. Недостатком является то, что функции не могут храниться в качестве ключей в доступных структурах данных.

Когда один из ключей — функция, функция вызывается. В примере ниже мы используем функцию для получения и увеличения всех возрастов в списке:

iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> all = fn :get_and_update, data, next ->
...>   data |> Enum.map(next) |> Enum.unzip()
...> end
iex> get_and_update_in(users, [all, :age], &{&1, &1 + 1})
{[27, 23], [%{name: "john", age: 28}, %{name: "meg", age: 24}]}

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

Модуль Access поставляется со многими удобными функциями доступа, такими как анонимная функция all , определённая выше. См. Access.all/0, Access.key/2 и другие в качестве примеров.

get_in(data, keys)Source

@spec get_in(Access.t(), [term(), ...]) :: term()

Получает значение из вложенной структуры.

Использует модуль Access для обхода структур в соответствии с заданными keys, если key не является функцией, что подробно описано в последующем разделе.

Обратите внимание, что если ни один из заданных ключей не является функцией, редко бывает причина использовать get_in вместо написания обычного кода Elixir с использованием [].

Примеры

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users, ["john", :age])
27
iex> # Equivalent to:
iex> users["john"][:age]
27

get_in/2 также может использовать средства доступа в модуле Access для обхода более сложных структур данных. Например, здесь мы используем Access.all/0 для обхода списка:

iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> get_in(users, [Access.all(), :age])
[27, 23]

В случае, если любой из компонентов возвращает nil, nil будет возвращено, и get_in/2 не будет продолжать обход:

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users, ["unknown", :age])
nil
iex> # Equivalent to:
iex> users["unknown"][:age]
nil

iex> users = nil
iex> get_in(users, [Access.all(), :age])
nil

В качестве альтернативы, если вам нужно получить доступ к сложным структурам данных, вы можете использовать сопоставление с образцом:

case users do
  %{"john" => %{age: age}} -> age
  _ -> default_value
end

Функции в качестве ключей

Если ключ, переданный get_in/2, является функцией, функция будет вызвана с тремя аргументами:

  • операция (:get)
  • данные для доступа
  • функция, которая будет вызвана далее

Это означает, что get_in/2 можно расширить для предоставления настраиваемых поисков. Именно так и работает ключ Access.all/0 в предыдущем разделе. Например, мы можем вручную реализовать такой обход следующим образом:

iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> all = fn :get, data, next -> Enum.map(data, next) end
iex> get_in(users, [all, :age])
[27, 23]

Модуль Access поставляется со многими удобными функциями доступа. См. Access.all/0, Access.key/2 и другие в качестве примеров.

Работа со структурами

По умолчанию структуры не реализуют поведение Access, необходимое для этой функции. Поэтому вы не можете сделать так:

get_in(some_struct, [:some_key, :nested_key])

Хорошая новость заключается в том, что структуры имеют предопределённую форму. Поэтому вы можете написать вместо этого:

some_struct.some_key.nested_key

Если some_key может вернуть nil, вы всегда можете перейти к сопоставлению с образцом, чтобы обеспечить обработку вложенных структур:

case some_struct do
  %{some_key: %{nested_key: value}} -> value
  %{} -> nil
end

if(condition, clauses)Source

Предоставляет макрос if/2.

Этот макрос ожидает, что первый аргумент будет условием, а второй — списком ключевых слов.

Примеры однострочных выражений

if(foo, do: bar)

В примере выше, bar будет возвращено, если foo вычисляется как истинное значение (ни false ни nil). В противном случае, будет возвращено nil.

Можно указать опцию else, чтобы указать обратное:

if(foo, do: bar, else: baz)

Примеры блоков

Также можно передать блок в макрос if/2. Первый пример выше будет переведён в:

if foo do
  bar
end

Обратите внимание, что do-end становятся разделителями. Второй пример будет переведён в:

if foo do
  bar
else
  baz
end

Для сравнения более двух пунктов необходимо использовать макрос cond/1.

inspect(term, opts \\ [])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>
END_OF_DOCUMENT_MARKER

match?(pattern, expr)Source

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

Примеры

iex> match?(1, 1)
true

iex> match?({1, _}, {1, 2})
true

iex> map = %{a: 1, b: 2}
iex> match?(%{a: _}, map)
true

iex> a = 1
iex> match?(^a, 1)
true

match?/2 очень полезен при фильтрации или поиске значения в перечисляемом объекте:

iex> list = [a: 1, b: 2, a: 3]
iex> Enum.filter(list, &match?({:a, _}, &1))
[a: 1, a: 3]

Для соответствия также можно задать условия:

iex> list = [a: 1, b: 2, a: 3]
iex> Enum.filter(list, &match?({:a, x} when x < 2, &1))
[a: 1]

Переменные, присвоенные в соответствии, недоступны за пределами вызова функции (в отличие от обычного сопоставления с образцом с оператором =):

iex> match?(_x, 1)
true
iex> binding()
[]

Значения против шаблонов

Помните, что оператор привязки соответствует значениям, а не шаблонам. Передача переменной в качестве шаблона всегда вернёт true и вызовет предупреждение о том, что переменная не используется:

# don't do this
pattern = %{a: :a}
match?(pattern, %{b: :b})

Аналогично, перемещение выражения из шаблона может больше не сохранять его семантику. Например:

match?([_ | _], [1, 2, 3])
#=> true

pattern = [_ | _]
match?(pattern, [1, 2, 3])
** (CompileError) invalid use of _. _ can only be used inside patterns to ignore values and cannot be used in expressions. Make sure you are inside a pattern or change it accordingly

Ещё один пример: карта в качестве шаблона выполняет частичное соответствие, но не после присвоения переменной:

match?(%{x: 1}, %{x: 1, y: 2})
#=> true

attrs = %{x: 1}
match?(^attrs, %{x: 1, y: 2})
#=> false

Оператор привязки проверит, равны ли значения, используя ===/2, в то время как шаблоны имеют свои собственные правила при сопоставлении карт, списков и так далее. Такое поведение не специфично для match?/2. Следующий код также выбросит исключение:

attrs = %{x: 1}
^attrs = %{x: 1, y: 2}
#=> (MatchError) no match of right hand side value: %{x: 1, y: 2}

max(first, second)Source

@spec max(first, second) :: first | second when first: term(), second: term()

Возвращает наибольшее из двух заданных терминов в соответствии с их структурным сравнением.

Если термины равны, возвращается первый.

Выполняет структурное сравнение, где все термины Elixir могут быть сравнены друг с другом. Дополнительную информацию см. в разделе "Структурное сравнение".

Встроено компилятором.

Примеры

iex> max(1, 2)
2
iex> max(:a, :b)
:b

min(first, second)Source

@spec min(first, second) :: first | second when first: term(), second: term()

Возвращает наименьшее из двух заданных терминов в соответствии с их структурным сравнением.

Если термины равны, возвращается первый.

Выполняет структурное сравнение, где все термины Elixir могут быть сравнены друг с другом. Дополнительную информацию см. в разделе "Структурное сравнение".

Встроено компилятором.

Примеры

iex> min(1, 2)
1
iex> min("foo", "bar")
"bar"

pop_in(path)Source

Удаляет ключ из вложенной структуры по заданному path.

Аналогично pop_in/2, за исключением того, что путь извлекается с помощью макроса, а не передаётся в виде списка. Например:

pop_in(opts[:foo][:bar])

Эквивалентно:

pop_in(opts, [:foo, :bar])

Обратите внимание, что для работы этого макроса весь путь должен всегда быть видим этим макросом. Дополнительную информацию о поддерживаемых выражениях пути см. в документации get_and_update_in/2.

Примеры

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> pop_in(users["john"][:age])
{27, %{"john" => %{}, "meg" => %{age: 23}}}

iex> users = %{john: %{age: 27}, meg: %{age: 23}}
iex> pop_in(users.john[:age])
{27, %{john: %{}, meg: %{age: 23}}}

В случае, если какой-либо элемент возвращает nil, его ключ будет удалён, и удаление будет считаться успешным.

pop_in(data, keys)Source

@spec pop_in(data, [Access.get_and_update_fun(term(), data) | term(), ...]) ::
  {term(), data}
when data: Access.container()

Удаляет ключ из заданной вложенной структуры.

Использует протокол Access для обхода структур в соответствии с заданным keys, если key не является функцией. Если ключ является функцией, она будет вызвана так, как указано в get_and_update_in/3.

Примеры

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> pop_in(users, ["john", :age])
{27, %{"john" => %{}, "meg" => %{age: 23}}}

В случае, если какой-либо элемент возвращает nil, его ключ будет удалён, и удаление будет считаться успешным.

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> pop_in(users, ["jane", :age])
{nil, %{"john" => %{age: 27}, "meg" => %{age: 23}}}

put_elem(tuple, index, value)Source

@spec put_elem(tuple(), non_neg_integer(), term()) :: tuple()

Вставляет value в заданный нулевой индекс index в tuple.

Встроено компилятором.

Примеры

iex> tuple = {:foo, :bar, 3}
iex> put_elem(tuple, 0, :baz)
{:baz, :bar, 3}

put_in(path, value)Source

Вставляет значение во вложенную структуру по заданному path.

Аналогично put_in/3, за исключением того, что путь извлекается с помощью макроса, а не передаётся в виде списка. Например:

put_in(opts[:foo][:bar], :baz)

Эквивалентно:

put_in(opts, [:foo, :bar], :baz)

Это также работает со вложенными структурами и способом указания путей через struct.path.to.value:

put_in(struct.foo.bar, :baz)

Обратите внимание, что для работы этого макроса весь путь должен всегда быть видим этим макросом. Дополнительную информацию о поддерживаемых выражениях пути см. в документации get_and_update_in/2.

Примеры

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users["john"][:age], 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}}

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users["john"].age, 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}}

put_in(data, keys, value)Source

@spec put_in(Access.t(), [term(), ...], term()) :: Access.t()

Вставляет значение во вложенную структуру.

Использует модуль Access для обхода структур в соответствии с заданным keys, если key не является функцией. Если ключ является функцией, она будет вызвана так, как указано в get_and_update_in/3.

Примеры

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users, ["john", :age], 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}}

Если любое из промежуточных значений равно nil, будет выброшено исключение:

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users, ["jane", :age], "oops")
** (ArgumentError) could not put/update key :age on a nil value

raise(message)Source

Выбрасывает исключение.

Если message — строка, выбросит исключение RuntimeError с ней.

Если message — атом, просто вызовет raise/2 с атомом в качестве первого аргумента и [] в качестве второго.

Если message — структура исключения, она выбросится как есть.

Если message — что-либо ещё, raise завершится исключением ArgumentError.

Примеры

iex> raise "oops"
** (RuntimeError) oops

try do
  1 + :foo
rescue
  x in [ArithmeticError] ->
    IO.puts("that was expected")
    raise x
end

raise(exception, attributes)Source

Выбрасывает исключение.

Вызывает функцию exception/1 для заданного аргумента (который должен быть именем модуля, как ArgumentError или RuntimeError), передавая attributes для получения структуры исключения.

Любой модуль, содержащий вызов макроса defexception/1, автоматически реализует обратный вызов Exception.exception/1, ожидаемый raise/2. Дополнительную информацию см. в defexception/1.

Примеры

iex> raise(ArgumentError, "Sample")
** (ArgumentError) Sample

reraise(message, stacktrace)Source

Выбрасывает исключение, сохраняя предыдущий стек вызовов.

Работает как raise/1, но не генерирует новый стек вызовов.

Обратите внимание, что __STACKTRACE__ может использоваться внутри catch/rescue для получения текущего стека вызовов.

Примеры

try do
  raise "oops"
rescue
  exception ->
    reraise exception, __STACKTRACE__
end

reraise(exception, attributes, stacktrace)Source

Выбрасывает исключение, сохраняя предыдущий стек вызовов.

reraise/3 работает как reraise/2, за исключением того, что он передаёт аргументы функции exception/1 так, как описано в raise/2.

Примеры

try do
  raise "oops"
rescue
  exception ->
    reraise WrapperError, [exception: exception], __STACKTRACE__
end
END_OF_DOCUMENT_MARKER

send(dest, message)Source

@spec send(dest :: Process.dest(), message) :: message when message: any()

Отправляет сообщение заданному dest и возвращает сообщение.

dest может быть удалённым или локальным PID, локальным портом, локально зарегистрированным именем или кортежем в формате {registered_name, node} для зарегистрированного имени на другом узле.

Компилируется встраиваемо.

Примеры

iex> send(self(), :hello)
:hello

sigil_C(term, modifiers)Source

Обрабатывает сигил ~C для списков символов.

Возвращает список символов без интерполяций и без управляющих символов, за исключением экранирования закрывающего символа сигила.

Список символов — это список целых чисел, где все целые числа являются допустимыми кодовыми точками. Три выражения ниже эквивалентны:

~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 (таких как экранирование + или ?) и также требует от вас экранировать закрывающий символ сигила, если он встречается в Regex.

Дополнительную информацию о регулярных выражениях можно найти в модуле Regex.

Примеры

iex> Regex.match?(~R(f#{1,3}o), "f#o")
true

sigil_r(term, modifiers)Source

Обрабатывает сигил ~r для регулярных выражений.

Возвращает шаблон регулярного выражения, убирая экранирование символов и заменяя интерполяции.

Дополнительную информацию о регулярных выражениях можно найти в модуле Regex.

Примеры

iex> Regex.match?(~r/foo/, "foo")
true

iex> Regex.match?(~r/a#{:b}c/, "abc")
true

Хотя сигил ~r позволяет использовать скобки и квадратные скобки в качестве разделителей, предпочтительнее использовать " или / для избежания конфликтов с экранированием служебных символов regex.

sigil_S(term, modifiers)Source

Обрабатывает сигил ~S для строк.

Возвращает строку без интерполяций и без управляющих символов, за исключением экранирования закрывающего символа сигила.

Примеры

iex> ~S(foo)
"foo"
iex> ~S(f#{o}o)
"f\#{o}o"
iex> ~S(\o/)
"\\o/"

Однако, если вы хотите повторно использовать сам символ сигила в строке, вам нужно его экранировать:

iex> ~S((\))
"()"

sigil_s(term, modifiers)Source

Обрабатывает сигил ~s для строк.

Возвращает строку так, как будто это строка в двойных кавычках, убирая экранирование символов и заменяя интерполяции.

Примеры

iex> ~s(foo)
"foo"

iex> ~s(f#{:o}o)
"foo"

iex> ~s(f\#{:o}o)
"f\#{:o}o"

sigil_T(time_string, modifiers)Source

Обрабатывает сигил ~T для времён.

По умолчанию этот сигил использует встроенный Calendar.ISO, который требует, чтобы времена были записаны в формате ISO8601:

~T[hh:mm:ss]
~T[hh:mm:ss.ssssss]

например:

~T[13:00:07]
~T[13:00:07.123]

Если вы используете альтернативные календари, можно использовать любую запись, при условии, что за записью следует пробел и имя календаря:

~T[SOME-REPRESENTATION My.Alternative.Calendar]

Вариант с маленькой буквой ~t не существует, так как интерполяции и управляющие символы не нужны для сигилов времён.

Дополнительную информацию о временах можно найти в модуле Time.

Примеры

iex> ~T[13:00:07]
~T[13:00:07]
iex> ~T[13:00:07.001]
~T[13:00:07.001]

sigil_U(datetime_string, modifiers)Source

Обрабатывает сигил ~U для создания UTC DateTime.

По умолчанию этот сигил использует встроенный Calendar.ISO, который требует, чтобы UTC даты и времена были записаны в формате ISO8601:

~U[yyyy-mm-dd hh:mm:ssZ]
~U[yyyy-mm-dd hh:mm:ss.ssssssZ]
~U[yyyy-mm-ddThh:mm:ss.ssssss+00:00]

например:

~U[2015-01-13 13:00:07Z]
~U[2015-01-13T13:00:07.123+00:00]

Если вы используете альтернативные календари, можно использовать любую запись, при условии, что за записью следует пробел и имя календаря:

~U[SOME-REPRESENTATION My.Alternative.Calendar]

Указанное datetime_string должно содержать «Z» или «00:00», что отмечает его как UTC, в противном случае возникает ошибка.

Вариант с маленькой буквой ~u не существует, так как интерполяции и управляющие символы не нужны для сигилов дат и времён.

Дополнительную информацию о датах и временах можно найти в модуле DateTime.

Примеры

iex> ~U[2015-01-13 13:00:07Z]
~U[2015-01-13 13:00:07Z]
iex> ~U[2015-01-13T13:00:07.001+00:00]
~U[2015-01-13 13:00:07.001Z]

sigil_W(term, modifiers)Source

Обрабатывает сигил ~W для списков слов.

Возвращает список «слов», разделённых пробелами, без интерполяций и без управляющих символов, за исключением экранирования закрывающего символа сигила.

Модификаторы

  • s: слова в списке — это строки (по умолчанию)
  • a: слова в списке — это атомы
  • c: слова в списке — это списки символов

Примеры

iex> ~W(foo #{bar} baz)
["foo", "\#{bar}", "baz"]
END_OF_DOCUMENT_MARKER

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

Запускает заданную функцию и возвращает её PID.

Как правило, разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большими удобствами в плане интроспекции и отладки.

См. модуль Process для получения дополнительных функций, связанных с процессами.

Анонимная функция принимает 0 аргументов и может возвращать любое значение.

Встраивается компилятором.

Примеры

current = self()
child = spawn(fn -> send(current, {self(), 1 + 2}) end)

receive do
  {^child, 3} -> IO.puts("Received 3 back")
end

spawn(module, fun, args)Source

@spec spawn(module(), atom(), list()) :: pid()

Запускает заданную функцию fun из данного module, передавая ей данные args, и возвращает её PID.

Как правило, разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большими удобствами в плане интроспекции и отладки.

См. модуль Process для получения дополнительных функций, связанных с процессами.

Встраивается компилятором.

Примеры

spawn(SomeModule, :function, [1, 2, 3])

spawn_link(fun)Source

@spec spawn_link((-> any())) :: pid()

Запускает заданную функцию, связывает её с текущим процессом и возвращает её PID.

Как правило, разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большими удобствами в плане интроспекции и отладки.

См. модуль Process для получения дополнительных функций, связанных с процессами. Для получения дополнительной информации о связывании см. Process.link/1.

Анонимная функция принимает 0 аргументов и может возвращать любое значение.

Встраивается компилятором.

Примеры

current = self()
child = spawn_link(fn -> send(current, {self(), 1 + 2}) end)

receive do
  {^child, 3} -> IO.puts("Received 3 back")
end

spawn_link(module, fun, args)Source

@spec spawn_link(module(), atom(), list()) :: pid()

Запускает заданную функцию fun из данного module, передавая ей данные args, связывает её с текущим процессом и возвращает её PID.

Как правило, разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большими удобствами в плане интроспекции и отладки.

См. модуль Process для получения дополнительных функций, связанных с процессами. Для получения дополнительной информации о связывании см. Process.link/1.

Встраивается компилятором.

Примеры

spawn_link(SomeModule, :function, [1, 2, 3])

spawn_monitor(fun)Source

@spec spawn_monitor((-> any())) :: {pid(), reference()}

Запускает заданную функцию, контролирует её и возвращает её PID и ссылку на мониторинг.

Как правило, разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большими удобствами в плане интроспекции и отладки.

См. модуль Process для получения дополнительных функций, связанных с процессами.

Анонимная функция принимает 0 аргументов и может возвращать любое значение.

Встраивается компилятором.

Примеры

current = self()
spawn_monitor(fn -> send(current, {self(), 1 + 2}) end)

spawn_monitor(module, fun, args)Source

@spec spawn_monitor(module(), atom(), list()) :: {pid(), reference()}

Запускает данный модуль и функцию, передавая данные args, контролирует её и возвращает её 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) или самой struct. Вторым аргументом является любой Enumerable, который выдает кортежи из двух элементов (пары ключ-значение) во время перечисления.

Ключи в Enumerable, которые не существуют в структуре, автоматически отбрасываются. Обратите внимание, что ключи должны быть атомами, так как только атомы разрешены при определении структуры. Если ключи в Enumerable дублируются, будет взята последняя запись (такое же поведение, как у Map.new/1).

Эта функция полезна для динамического создания и обновления структур, а также для преобразования карт в структуры; в последнем случае простого вставки соответствующего поля :__struct__ в карту может быть недостаточно, и вместо этого следует использовать struct/2.

Примеры

defmodule User do
  defstruct name: "john"
end

struct(User)
#=> %User{name: "john"}

opts = [name: "meg"]
user = struct(User, opts)
#=> %User{name: "meg"}

struct(user, unknown: "value")
#=> %User{name: "meg"}

struct(User, %{name: "meg"})
#=> %User{name: "meg"}

# String keys are ignored
struct(User, %{"name" => "meg"})
#=> %User{name: "john"}

struct!(struct, fields \\ [])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"

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

Помечает, что заданная переменная не должна подвергаться гигиенизации.

Этот макрос ожидает переменную и обычно вызывается внутри Kernel.SpecialForms.quote/2 для обозначения того, что переменная не должна подвергаться гигиенизации. См. Kernel.SpecialForms.quote/2 для получения дополнительной информации.

Примеры

iex> Kernel.var!(example) = 1
1
iex> Kernel.var!(example)
1

левый |> правыйИсточник

Оператор конвейера.

Данный оператор вводит выражение слева в качестве первого аргумента вызова функции справа.

Примеры

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

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

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

Обеспечивает оператор короткого замыкания, который вычисляет и возвращает второе выражение только в том случае, если первое выражение не оценивается как истинное значение (то есть, оно либо nil , либо false). В противном случае возвращает первое выражение.

Запрещён в условиях guard.

Примеры

iex> Enum.empty?([1]) || Enum.empty?([1])
false

iex> List.first([]) || true
true

iex> Enum.empty?([1]) || 1
1

iex> Enum.empty?([]) || throw(:bad)
true

Обратите внимание, что в отличие от or/2, этот оператор принимает в качестве первого аргумента любое выражение, а не только булевы значения.

© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.15.4/Kernel.html

Spec-Zone.ru

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