Spec-Zone.ru › Elixir 1.16

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

Kernel является стандартной средой Elixir.

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

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

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

iex> is_number(13)
true

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

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

Дополнительную информацию об импорте см. в import/2.

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

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

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

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

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

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

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

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

Типы данных

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

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

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

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

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

Протоколы

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

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

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

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

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

Вспомогательные документы

В разделе "Страницы" на боковой панели вы найдете учебные пособия, руководства и справочные документы, которые более подробно описывают семантику и поведение Elixir. Это:

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

Проверки

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

def drive(%User{age: age}) when age >= 16 do
  ...
end

Приведенная выше строка будет вызвана только в том случае, если возраст пользователя не меньше 16 лет. Проверки также поддерживают объединение нескольких условий с помощью and и or. Вся проверка истинна, если все выражения проверки будут оценены как true. Более подробное введение в проверки доступно на странице Шаблоны и проверки.

Истинностные и ложные значения

Помимо булевых значений true и false, Elixir имеет понятие «истинностного» или «ложного» значения.

  • значение является истинностным, когда оно не является false или nil
  • значение является ложным, когда оно является либо false или nil

Elixir имеет функции, такие как and/2, которые работают только с булевыми значениями, но также функции, которые работают с истинностными/ложными значениями, такие как &&/2 и !/1.

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

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

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 с длиной size.

bit_size(bitstring)

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

byte_size(bitstring)

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

ceil(number)

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

div(dividend, divisor)

Производит целочисленное деление.

elem(tuple, index)

Получает элемент в позиции с нулевой базой index в tuple.

floor(number)

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

hd(list)

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

left in right

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

is_atom(term)

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

is_binary(term)

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

is_bitstring(term)

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

is_boolean(term)

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

is_exception(term)

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

is_exception(term, name)

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

is_float(term)

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

is_function(term)

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

is_function(term, arity)

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

is_integer(term)

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

is_list(term)

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

is_map(term)

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

is_map_key(map, key)

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

is_nil(term)

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

is_number(term)

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

is_pid(term)

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

is_port(term)

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

is_reference(term)

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

END_OF_DOCUMENT_MARKER
is_struct(term)

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

is_struct(term, name)

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

is_tuple(term)

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

length(list)

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

map_size(map)

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

node()

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

node(arg)

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

not value

Строго булевый оператор «не».

left or right

Строго булевый оператор «или».

rem(dividend, divisor)

Вычисляет остаток от целочисленного деления.

round(number)

Округляет число до ближайшего целого.

self()

Возвращает PID (идентификатор процесса) вызывающего процесса.

tl(list)

Возвращает хвост списка. Вызывает ArgumentError, если список пуст.

trunc(number)

Возвращает целую часть number.

tuple_size(tuple)

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

Функции

left && right

Логический оператор "и".

base ** exponent

Оператор возведения в степень.

left ++ right

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

left -- right

Оператор вычитания из списка. Удаляет первое вхождение элемента слева для каждого элемента справа.

..

Создаёт диапазон полного среза 0..-1//1.

first..last

Создаёт диапазон от first до last.

first..last//step

Создаёт диапазон от first до last с шагом step.

!value

Логический оператор "не".

left <> right

Бинарный оператор конкатенации. Объединяет два двоичных числа.

left =~ right

Оператор сопоставления по тексту. Сопоставляет термин слева со строкой или регулярным выражением справа. left, right.

@expr

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

alias!(alias)

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

apply(fun, args)

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

apply(module, function_name, args)

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

binary_slice(binary, range)

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

binary_slice(binary, start, size)

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

binding(context \\ nil)

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

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

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

def(call, expr \\ nil)

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

defdelegate(funs, opts)

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

defexception(fields)

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

defguard(guard)

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

defguardp(guard)

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

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

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

defmacro(call, expr \\ nil)

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

defmacrop(call, expr \\ nil)

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

defmodule(alias, do_block)

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

defoverridable(keywords_or_behaviour)

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

defp(call, expr \\ nil)

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

defprotocol(name, do_block)

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

defstruct(fields)

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

destructure(left, right)

Деструктурирует два списка, присваивая каждый элемент справа соответствующему элементу слева.

exit(reason)

Останавливает выполнение вызывающего процесса по указанной причине.

function_exported?(module, function, arity)

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

get_and_update_in(path, fun)

Получает значение и обновляет вложенную структуру данных через заданную path.

get_and_update_in(data, keys, fun)

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

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

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

END_OF_DOCUMENT_MARKER
pop_in(path)

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

pop_in(data, keys)

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

put_elem(tuple, index, value)

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

put_in(path, value)

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

put_in(data, keys, value)

Размещает значение в вложенную структуру.

raise(message)

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

raise(exception, attributes)

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

reraise(message, stacktrace)

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

reraise(exception, attributes, stacktrace)

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

send(dest, message)

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

sigil_C(term, modifiers)

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

sigil_c(term, modifiers)

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

sigil_D(date_string, modifiers)

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

sigil_N(naive_datetime_string, modifiers)

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

sigil_r(term, modifiers)

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

sigil_S(term, modifiers)

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

sigil_s(term, modifiers)

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

sigil_T(time_string, modifiers)

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

sigil_U(datetime_string, modifiers)

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

sigil_W(term, modifiers)

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

sigil_w(term, modifiers)

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

spawn(fun)

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

spawn(module, fun, args)

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

spawn_link(fun)

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

spawn_link(module, fun, args)

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

spawn_monitor(fun)

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

spawn_monitor(module, fun, args)

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

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

Логический оператор «или».

END_OF_DOCUMENT_MARKER

Охранники

left * rightSource

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

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

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

Примеры

iex> 1 * 2
2

+valueSource

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

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

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

Примеры

iex> +1
1

left + rightSource

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

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

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

Примеры

iex> 1 + 2
3

-valueSource

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

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

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

Примеры

iex> -2
-2

left - rightSource

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

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

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

Примеры

iex> 1 - 2
-1

left / rightSource

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

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

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

Возбуждает исключение ArithmeticError, если right равно 0 или 0.0.

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

Примеры

1 / 2
#=> 0.5

-3.0 / 2.0
#=> -1.5

5 / 1
#=> 5.0

7 / 0
** (ArithmeticError) bad argument in arithmetic expression

left != rightSource

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

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

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

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

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

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

Примеры

iex> 1 != 2
true

iex> 1 != 1.0
false

left !== rightSource

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

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

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

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

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

Примеры

iex> 1 !== 2
true

iex> 1 !== 1.0
true

left < rightSource

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

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

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

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

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

Примеры

iex> 1 < 2
true

left <= rightSource

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

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

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

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

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

Примеры

iex> 1 <= 2
true

left == rightSource

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

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

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

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

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

Примеры

iex> 1 == 2
false

iex> 1 == 1.0
true

left === rightSource

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

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

Возвращает true если два значения строго равны.

Значения считаются строго равными только в случае одинакового значения и типа. Например, 1 == 1.0 возвращает true, но, поскольку типы разные, 1 === 1.0 возвращает false.

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

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

Примеры

iex> 1 === 2
false

iex> 1 === 1.0
false

left > rightSource

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

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

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

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

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

Примеры

iex> 1 > 2
false

left >= rightSource

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

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

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

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

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

Примеры

iex> 1 >= 2
false

abs(число)Source

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

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

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

Примеры

iex> abs(-3.33)
3.33

iex> abs(-3)
3
END_OF_DOCUMENT_MARKER

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

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

Если left является false, возвращает false; в противном случае возвращает right.

Требуется только, чтобы операнд left был булевым, так как он выполняется по короткой схеме. Если операнд left не является булевым, генерируется исключение BadBooleanError.

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

Примеры

iex> true and false
false

iex> true and "yay!"
"yay!"

iex> "yay!" and true
** (BadBooleanError) expected a boolean on left-side of "and", got: "yay!"

binary_part(бинарный, начало, длина)Исходный код

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

Извлекает часть бинарного объекта по start с size.

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

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

Примеры

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

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

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

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

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

bit_size(битовая строка)Исходный код

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

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

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

Примеры

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

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

byte_size(битовая строка)Исходный код

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

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

То есть, если количество битов в bitstring не делится на 8, количество байтов округляется вверх.

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

Примеры

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

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

ceil(число)Исходный код

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

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

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

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

Примеры

iex> ceil(10)
10

iex> ceil(10.1)
11

iex> ceil(-10.1)
-10

div(делимое, делитель)Исходный код

@spec div(integer(), neg_integer() | pos_integer()) :: integer()

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

Генерирует исключение ArithmeticError, если один из аргументов не является целым числом или когда divisor является 0.

div/2 выполняет обрезанное целочисленное деление. Это означает, что результат всегда округляется к нулю.

Если нужно выполнить целочисленное деление с округлением к меньшему целому, используйте Integer.floor_div/2.

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

Примеры

div(5, 2)
#=> 2

div(6, -4)
#=> -1

div(-99, 2)
#=> -49

div(100, 0)
** (ArithmeticError) bad argument in arithmetic expression

elem(кортеж, индекс)Исходный код

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

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

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

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

Примеры

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

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

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

floor(число)Исходный код

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

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

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

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

Примеры

iex> floor(10)
10

iex> floor(9.7)
9

iex> floor(-9.7)
-10

hd(список)Исходный код

@spec hd(nonempty_maybe_improper_list(elem, any())) :: elem when elem: term()

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

Голова списка — это его первый элемент.

Работает со списками любого типа.

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

Примеры

hd([1, 2, 3, 4])
#=> 1

hd([1 | 2])
#=> 1

При пустом списке генерируется:

hd([])
** (ArgumentError) argument error

левое в правомИсходный код

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

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

Примеры

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

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

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

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

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

Условие

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

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

when x in [1, 2, 3]

переводится в:

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

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

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

when x in 1..1000

переводится приблизительно в:

when x >= 1 and x <= 1000

Учёт AST

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

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

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

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

is_atom(термин)Исходный код

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

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

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

Примеры

iex> is_atom(false)
true

iex> is_atom(:name)
true

iex> is_atom(AnAtom)
true

iex> is_atom("true")
false

is_binary(термин)Исходный код

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

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

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

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

Примеры

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

is_bitstring(термин)Исходный код

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

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

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

Примеры

iex> is_bitstring("foo")
true
iex> is_bitstring(<<1::3>>)
true
END_OF_DOCUMENT_MARKER

is_boolean(term)Source

@spec is_boolean(term()) :: boolean()

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

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

Примеры

iex> is_boolean(false)
true

iex> is_boolean(true)
true

iex> is_boolean(:test)
false

is_exception(term)Source

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

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

Примеры

iex> is_exception(%RuntimeError{})
true

iex> is_exception(%{})
false

is_exception(term, name)Source

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

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

Примеры

iex> is_exception(%RuntimeError{}, RuntimeError)
true

iex> is_exception(%RuntimeError{}, Macro.Env)
false

is_float(term)Source

@spec is_float(term()) :: boolean()

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

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

is_function(term)Source

@spec is_function(term()) :: boolean()

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

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

Примеры

iex> is_function(fn x -> x + x end)
true

iex> is_function("not a function")
false

is_function(term, arity)Source

@spec is_function(term(), non_neg_integer()) :: boolean()

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

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

Примеры

iex> is_function(fn x -> x * 2 end, 1)
true
iex> is_function(fn x -> x * 2 end, 2)
false

is_integer(term)Source

@spec is_integer(term()) :: boolean()

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

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

is_list(term)Source

@spec is_list(term()) :: boolean()

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

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

is_map(term)Source

@spec is_map(term()) :: boolean()

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

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

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

Оператор строгого логического "не".

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

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

Примеры

iex> not false
true

left or rightSource

Оператор строгого логического "или".

Если left является true, возвращается true; в противном случае возвращается right.

Требуется, чтобы только left операнд был булевым, так как он выполняет короткое замыкание. Если left операнд не является булевым, генерируется исключение BadBooleanError.

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

Примеры

iex> true or false
true

iex> false or 42
42

iex> 42 or false
** (BadBooleanError) expected a boolean on left-side of "or", got: 42

rem(dividend, divisor)Source

@spec rem(integer(), neg_integer() | pos_integer()) :: integer()

Вычисляет остаток от целочисленного деления.

rem/2 использует усеченное деление, что означает, что результат всегда будет иметь знак dividend.

Генерирует исключение ArithmeticError, если один из аргументов не является целым числом или если divisor равно 0.

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

Примеры

iex> rem(5, 2)
1
iex> rem(6, -4)
2

round(number)Source

@spec round(number()) :: integer()

Округляет число до ближайшего целого.

Если число равноудалено от двух ближайших целых чисел, округляется от нуля.

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

Примеры

iex> round(5.6)
6

iex> round(5.2)
5

iex> round(-9.9)
-10

iex> round(-9)
-9

iex> round(2.5)
3

iex> round(-2.5)
-3

self()Source

@spec self() :: pid()

Возвращает PID (идентификатор процесса) вызывающего процесса.

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

tl(list)Source

@spec tl(nonempty_maybe_improper_list(elem, last)) ::
  maybe_improper_list(elem, last) | last
when elem: term(), last: term()

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

Хвостом списка является список без его первого элемента.

Работает со списками нестандартного вида.

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

Примеры

tl([1, 2, 3, :go])
#=> [2, 3, :go]

tl([:one])
#=> []

tl([:a, :b | :improper_end])
#=> [:b | :improper_end]

tl([:a | %{b: 1}])
#=> %{b: 1}

Передача пустого списка генерирует:

tl([])
** (ArgumentError) argument error

trunc(number)Source

@spec trunc(number()) :: integer()

Возвращает целую часть number.

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

Примеры

iex> trunc(5.4)
5

iex> trunc(-5.99)
-5

iex> trunc(-5)
-5

tuple_size(tuple)Source

@spec tuple_size(tuple()) :: non_neg_integer()

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

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

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

Примеры

iex> tuple_size({:a, :b, :c})
3

Функции

left && rightSource

Оператор логического "и".

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

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

Примеры

iex> Enum.empty?([]) && Enum.empty?([])
true

iex> List.first([]) && true
nil

iex> Enum.empty?([]) && List.first([1])
1

iex> false && throw(:bad)
false

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

base ** exponentSource

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

Оператор возведения в степень.

Принимает два числа в качестве входных данных. Если оба являются целыми числами, а правая часть (exponent) также больше или равна 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()

Оператор сопоставления по шаблону текста. Сопоставляет терм в left с регулярным выражением или строкой в right.

Если right является регулярным выражением, возвращает true, если left совпадает с right.

Если right является строкой, возвращает true, если true содержит 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

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

См. 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"

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

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

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

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

binary_slice(binary, start, size)Source

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

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

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

Примеры

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

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

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

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

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

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

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

binding(context \\ nil)Source

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

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

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

Примеры

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

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

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

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

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

Примеры

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

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

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

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

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

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

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

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

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

dbg внутри IEx

Вы можете настроить IEx на замену dbg своим IEx.pry/0 бэкендом, вызвав:

$ iex --dbg pry

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

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

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

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

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

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

Функция отладки может быть настроена во время компиляции через ключ :dbg_callback приложения :elixir. Функция отладки должна быть кортежем {module, function, args}. Функция function в module будет вызываться с тремя аргументами, предваряющими args,

  1. AST выражения code
  2. AST выражения options
  3. Среда Macro.Env области видимости, где вызывается dbg/2

Функция отладки вызывается во время компиляции, и она также должна возвращать AST. Ожидается, что AST в конечном итоге вернёт результат вычисления отлаживаемого выражения.

Вот простой пример:

defmodule MyMod do
  def debug_fun(code, options, caller, device) do
    quote do
      result = unquote(code)
      IO.inspect(unquote(device), result, label: unquote(Macro.to_string(code)))
    end
  end
end

Чтобы настроить функцию отладки:

# In config/config.exs
config :elixir, :dbg_callback, {MyMod, :debug_fun, [:stdio]}

Функция отладки по умолчанию

По умолчанию используемая функция отладки — Macro.dbg/3. Она просто выводит информацию о коде в стандартный вывод и возвращает значение, возвращённое при вычислении code. options используются для управления тем, как просматривать выражения. Они такие же, как опции, принимаемые inspect/2.

def(call, expr \\ nil)Source

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

Примеры

defmodule Foo do
  def bar, do: :baz
end

Foo.bar()
#=> :baz

Функция, ожидающая аргументы, может быть определена следующим образом:

defmodule Foo do
  def sum(a, b) do
    a + b
  end
end

В примере выше определена функция sum/2; эта функция получает два аргумента и возвращает их сумму.

Аргументы по умолчанию

\\ используется для задания значения по умолчанию для параметра функции. Например:

defmodule MyMath do
  def multiply_by(number, factor \\ 2) do
    number * factor
  end
end

MyMath.multiply_by(4, 3)
#=> 12

MyMath.multiply_by(4)
#=> 8

Компилятор преобразует это в несколько функций с разными арностью, например MyMath.multiply_by/1 и MyMath.multiply_by/2, которые представляют случаи, когда аргументы для параметров с значениями по умолчанию передаются или нет.

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

defmodule MyString do
  def join(string1, string2 \\ nil, separator \\ " ")

  def join(string1, nil, _separator) do
    string1
  end

  def join(string1, string2, separator) do
    string1 <> separator <> string2
  end
end

Обратите внимание, что \\ нельзя использовать с анонимными функциями, так как они могут иметь только одну арность.

Списки ключевых слов с аргументами по умолчанию

Функции, содержащие много аргументов, могут извлечь выгоду из использования списков Keyword для группировки и передачи атрибутов в виде одного значения.

defmodule MyConfiguration do
  @default_opts [storage: "local"]

  def configure(resource, opts \\ []) do
    opts = Keyword.merge(@default_opts, opts)
    storage = opts[:storage]
    # ...
  end
end

Разница между использованием Map и Keyword для хранения многих аргументов заключается в ключах Keyword:

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

Имена функций

Имена функций и переменных в Elixir должны начинаться с подчеркивания или буквы Unicode, которая не находится в верхнем или прописном регистре. Они могут продолжаться с последовательностью букв Unicode, цифр и подчеркиваний. Они могут заканчиваться на ? или !. Стили руководства по написанию кода Elixir рекомендуют использовать snake_case формат для имён функций и переменных.

rescue/catch/after/else

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

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

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

defdelegate(funs, opts)Source

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

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

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

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

Опции

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

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

Примеры

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

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

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

defexception(fields)Source

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

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

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

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

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

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

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

defmodule MyAppError do
  defexception [:message]
end

value = [:hello]

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

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

defmodule MyAppError do
  defexception [:message]

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

raise MyAppError, value

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

END_OF_DOCUMENT_MARKER ```

defguard(guard)Source

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

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

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

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

Пример

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

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

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

  defp step(1, step_count) do
    step_count
  end

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

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

defguardp(guard)Source

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

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

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

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

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

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

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

defmacro(call, expr \\ nil)Source

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

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

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

Примеры

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

require MyLogic

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

defmacrop(call, expr \\ nil)Source

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

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

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

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

defmodule(alias, do_block)Source

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

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

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

Примеры

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

Number.one()
#=> 1

Number.two()
#=> 2

Имена и псевдонимы модулей

Имена модулей (и псевдонимы) должны начинаться с заглавной буквы ASCII, за которой могут следовать любые буквы ASCII, цифры или знак подчёркивания. Соглашения об именовании Elixir рекомендуют для имён модулей и псевдонимов использовать формат CamelCase.

Вы также можете использовать атомы в качестве имён модулей, но они должны содержать только символы ASCII.

Вложенность

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

defmodule Foo do
  defmodule Bar do
  end
end

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

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

defmodule Foo.Bar do
  # code
end

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

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

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

defmodule Module.concat(["Foo", "Bar"]) do
  # contents ...
end

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

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

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

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

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

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

defoverridable(keywords_or_behaviour)Source

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

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

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

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

Пример

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

      defoverridable test: 2
    end
  end
end

defmodule ChildMod do
  use DefaultMod

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

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

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

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

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

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

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

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

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

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

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

      defoverridable Behaviour
    end
  end
end

defmodule ChildMod do
  use DefaultMod

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

defp(call, expr \\ nil)Source

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

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

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

Примеры

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

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

Foo.bar()
#=> 3

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

defprotocol(name, do_block)Source

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

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

defstruct(fields)Source

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

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

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

Примеры

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

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

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

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

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

Добавьте документацию к структуре с помощью атрибута @doc, как для функции.

defmodule Post do
  @doc "A post. The content should be valid Markdown."
  defstruct [:title, :content, :author]
end

Наследование

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

john = %User{name: "John"}
MyProtocol.call(john)
** (Protocol.UndefinedError) protocol MyProtocol not implemented for %User{...}

defstruct/1, однако, позволяет реализовывать протоколы наследовать. Это можно сделать, определив атрибут @derive в виде списка перед вызовом defstruct/1:

defmodule User do
  @derive MyProtocol
  defstruct name: nil, age: nil
end

MyProtocol.call(john) # it works!

Общим примером является наследование протокола Inspect для скрытия определённых полей при выводе структуры:

defmodule User do
  @derive {Inspect, only: :name}
  defstruct name: nil, age: nil
end

Для каждого протокола в @derive, Elixir будет проверять, реализован ли протокол для Any. Если реализация протокола определяет обратный вызов __deriving__/3, обратный вызов будет вызван, и он должен определить модуль реализации. В противном случае реализация, которая просто указывает на реализацию Any, автоматически наследуется. Дополнительную информацию об обратном вызове __deriving__/3 см. в Protocol.derive/3.

Принудительное использование ключей

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

%User{name: "john", unknown: :key}
** (KeyError) key :unknown not found in: %User{age: 21, name: nil}

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

defmodule User do
  @enforce_keys [:name]
  defstruct name: nil, age: 10 + 11
end

Теперь попытка создать структуру без ключа name завершится ошибкой:

%User{age: 21}
** (ArgumentError) the following keys must also be given when building struct User: [:name]

Обратите внимание, что @enforce_keys — это просто гарантия на этапе компиляции, помогающая разработчикам при создании структур. Она не применяется к обновлениям и не обеспечивает никакой проверки значений.

Типы

Рекомендуется определять типы для структур. По соглашению, такой тип называется t. Для определения структуры внутри типа используется синтаксис литерала структуры:

defmodule User do
  defstruct name: "John", age: 25
  @type t :: %__MODULE__{name: String.t(), age: non_neg_integer}
end

Рекомендуется использовать синтаксис структуры только для определения типа структуры. При ссылке на другую структуру лучше использовать User.t() вместо %User{}.

Типы полей структуры, которые не включены в %User{}, по умолчанию имеют тип term() (см. term/0).

Для структур, внутренняя структура которых является приватной для локального модуля (сопоставление с образцом или прямой доступ к полям не должны быть разрешены), следует использовать атрибут @opaque. Для структур, внутренняя структура которых является публичной, следует использовать атрибут @type.

destructure(left, right)Source

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

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

Примеры

iex> destructure([x, y, z], [1, 2, 3, 4, 5])
iex> {x, y, z}
{1, 2, 3}

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

iex> destructure([x, y, z], [1])
iex> {x, y, z}
{1, nil, nil}

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

x = 1
destructure([^x, y, z], [1, 2, 3])

Приведённый выше пример будет работать только если x совпадает с первым значением правого списка. В противном случае он вызовет MatchError (как и оператор =).

exit(reason)Source

@spec exit(term()) :: no_return()

Останавливает выполнение вызывающего процесса с заданным значением причины.

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

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

Примеры

Когда процесс достигает конца, по умолчанию он завершается с причиной :normal. Вы также можете явно вызвать exit/1, если хотите завершить процесс, но не сигнализировать о какой-либо ошибке:

exit(:normal)

В случае возникновения ошибки, вы также можете использовать exit/1 с другой причиной:

exit(:seems_bad)

Если причина выхода не равна :normal, все процессы, связанные с выходящим процессом, потерпят крах (если они не обрабатывают выходы).

Выходы OTP

Выходы используются OTP для определения, завершился ли процесс аномально или нет. Следующие выходы считаются «нормальными»:

  • exit(:normal)
  • exit(:shutdown)
  • exit({:shutdown, term})

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

На этом поведении основано множество различных мест. Например, ExUnit использует exit(:shutdown) при выходе из процесса тестирования, чтобы сигнализировать связанным процессам, деревьям наблюдения и т. д. о вежливом завершении.

Выходы CLI

На основе сигналов выхода, упомянутых выше, если процесс, запущенный из командной строки, завершается с любой из трёх вышеупомянутых причин, его выход считается нормальным, и процесс операционной системы завершится со статусом 0.

Тем не менее, возможно настроить сигнал выхода операционной системы вызвав:

exit({:shutdown, integer})

Это заставит процесс операционной системы выйти со статусом, заданным integer, при этом сигнализируя всем связанным процессам Erlang о вежливом завершении.

Любая другая причина выхода приведет к выходу процесса операционной системы со статусом 1 и к краху связанных процессов Erlang.

function_exported?(module, function, arity)Source

@spec function_exported?(module(), atom(), arity()) :: boolean()

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

Обратите внимание, что эта функция не загружает модуль в случае его отсутствия. Подробнее см. Code.ensure_loaded/1.

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

Примеры

iex> function_exported?(Enum, :map, 2)
true

iex> function_exported?(Enum, :map, 10)
false

iex> function_exported?(List, :to_string, 1)
true

get_and_update_in(path, fun)Source

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

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

get_and_update_in(opts[:foo][:bar], &{&1, &1 + 1})

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

get_and_update_in(opts, [:foo, :bar], &{&1, &1 + 1})

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

get_and_update_in(struct.foo.bar, &{&1, &1 + 1})

Обратите внимание, что для работы этого макроса весь путь должен быть виден этому макросу. См. раздел «Пути» ниже.

Примеры

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

Пути

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

  • foo[bar] — обращается к ключу bar в foo; в случае, если foo равно null, возвращается 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()

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

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

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

Примеры

make_ref()
#=> #Reference<0.0.0.135>

match?(pattern, expr)Source

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

Примеры

iex> match?(1, 1)
true

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Другой пример: карта в качестве шаблона выполняет сопоставление подмножества, но не присваивается переменной:

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

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

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

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

max(first, second)Source

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

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

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

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

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

Примеры

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

min(first, second)Source

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

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

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

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

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

Примеры

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

pop_in(path)Source

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

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

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

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

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

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

Примеры

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

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

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

pop_in(data, keys)Source

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

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

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

Примеры

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

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

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

put_elem(tuple, index, value)Source

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

Устанавливает value по заданному нумерации (от 0) 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.

Примеры

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

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

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

sigil_S(term, modifiers)Source

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

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

Примеры

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

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

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

sigil_s(term, modifiers)Source

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

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

Примеры

iex> ~s(foo)
"foo"

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

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

sigil_T(time_string, modifiers)Source

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

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

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

например:

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

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

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

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

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

Примеры

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

sigil_U(datetime_string, modifiers)Source

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

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

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

например:

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

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

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

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

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

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

Примеры

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

sigil_W(term, modifiers)Source

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

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

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

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

Примеры

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

sigil_w(term, modifiers)Source

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

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

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

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

Примеры

iex> ~w(foo #{:bar} baz)
["foo", "bar", "baz"]

iex> ~w(foo #{" bar baz "})
["foo", "bar", "baz"]

iex> ~w(--source test/enum_test.exs)
["--source", "test/enum_test.exs"]

iex> ~w(foo bar baz)a
[:foo, :bar, :baz]

iex> ~w(foo bar baz)c
[~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()}

Запускает заданный модуль и функцию, передавая заданные аргументы, отслеживает её и возвращает её 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"]
END_OF_DOCUMENT_MARKER

throw(term)Source

@spec throw(term()) :: no_return()

Нелокальное возвращение из функции.

Использование throw/1 обычно не рекомендуется, так как оно позволяет функции выйти за пределы своего обычного потока выполнения, что затрудняет чтение кода. Кроме того, все сброшенные значения должны быть перехвачены try/catch. Дополнительную информацию см. в try/1.

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

to_charlist(term)Source

Преобразует заданный термин в charlist в соответствии с протоколом List.Chars.

Примеры

iex> to_charlist(:foo)
~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 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

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

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

Примеры

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

left |> rightSource

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

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

Примеры

iex> [1, [2], 3] |> List.flatten()
[1, 2, 3]

Приведённый выше пример эквивалентен вызову List.flatten([1, [2], 3]).

Оператор |>/2 в основном полезен, когда требуется выполнить ряд операций, напоминающих конвейер:

iex> [1, [2], 3] |> List.flatten() |> Enum.map(fn x -> x * 2 end)
[2, 4, 6]

В приведённом примере список [1, [2], 3] передаётся в качестве первого аргумента функции List.flatten/1, затем сглаженный список передаётся в качестве первого аргумента функции Enum.map/2, которая удваивает каждый элемент списка.

Другими словами, вышеприведённое выражение просто преобразуется в:

Enum.map(List.flatten([1, [2], 3]), fn x -> x * 2 end)

Возможные проблемы

Существует две распространённые проблемы при использовании оператора конвейера.

Первая связана с приоритетом операторов. Например, следующее выражение:

String.graphemes "Hello" |> Enum.reverse

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

String.graphemes("Hello" |> Enum.reverse())

что приводит к ошибке, так как протокол Enumerable не определён для двоичных данных. Добавление явных скобок разрешает неоднозначность:

String.graphemes("Hello") |> Enum.reverse()

Или, что ещё лучше:

"Hello" |> String.graphemes() |> Enum.reverse()

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

some_fun = &Regex.replace(~r/l/, &1, "L")
"Hello" |> some_fun.()

В качестве альтернативы можно использовать then/2 для того же эффекта:

some_fun = &Regex.replace(~r/l/, &1, "L")
"Hello" |> then(some_fun)

then/2 чаще всего используется, когда вы хотите передать в функцию, но значение ожидается вне первого аргумента, как в примере выше. Замените some_fun на его значение, и получим:

"Hello" |> then(&Regex.replace(~r/l/, &1, "L"))

left || rightSource

Логический оператор "или".

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

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

Примеры

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

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

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

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

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

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

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

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

Spec-Zone.ru

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