Ядро
Kernel — это стандартная среда выполнения Elixir.
Она в основном состоит из:
- базовых языковых примитивов, таких как арифметические операторы, создание процессов, обработка типов данных и другие
- макросов для управления потоком и определения новой функциональности (модулей, функций и т. п.)
- условий-фильтров для расширения сопоставления с образцом
Вы можете вызывать функции и макросы Kernel в любом месте кода Elixir без использования префикса Kernel., так как они были автоматически импортированы. Например, в IEx вы можете вызвать:
iex> is_number(13) true
Если вы не хотите импортировать функцию или макрос из Kernel, используйте опцию :except и затем перечислите функцию/макрос по арности:
import Kernel, except: [if: 2, unless: 2]
Дополнительную информацию об импорте см. в Kernel.SpecialForms.import/2.
В Elixir также есть специальные формы, которые всегда импортируются и не могут быть пропущены. Они описаны в Kernel.SpecialForms.
Стандартная библиотека
Kernel предоставляет базовые возможности, на которых построена стандартная библиотека Elixir. Рекомендуется изучить стандартную библиотеку для расширенной функциональности. Вот основные группы модулей в стандартной библиотеке (этот список не является полным справочником, см. боковую панель документации для всех записей).
Встроенные типы
Следующие модули обрабатывают встроенные типы данных Elixir:
-
Atom— литеральные константы с именем (true,false, иnilявляются атомами) -
Float— числа с плавающей точкой -
Function— ссылка на фрагмент кода, созданный с помощью специальной формыfn/1 -
Integer— целые числа (не дроби) -
List— коллекции переменного числа элементов (связанные списки) -
Map— коллекции пар ключ-значение -
Process— лёгкие потоки выполнения -
Port— механизмы взаимодействия с внешним миром -
Tuple— коллекции фиксированного числа элементов
Существуют два типа данных без сопровождающего модуля:
- Bitstring — последовательность битов, созданная с помощью
Kernel.SpecialForms.<<>>/1. Когда количество битов делится на 8, они называются двоичными и могут быть обработаны модулем Erlang: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
Фильтры
Этот модуль содержит встроенные фильтры, используемые разработчиками Elixir. Они представляют собой предопределённый набор функций и макросов, которые дополняют сопоставление с образцом, обычно вызываемые после оператора when. Например:
def drive(%User{age: age}) when age >= 16 do
...
end
Приведённый выше фрагмент кода будет вызван только в том случае, если возраст пользователя не менее 16 лет. Фильтры также поддерживают объединение нескольких условий с and и or. Весь фильтр истинен, если все выражения фильтра вычисляются как true. Более подробное введение в фильтры доступно на странице Шаблоны и фильтры.
Структурное сравнение
Функции сравнения в этом модуле выполняют структурное сравнение. Это означает, что структуры сравниваются на основе их представления, а не на их семантическом значении. Это особенно важно для функций, предназначенных для предоставления порядка, таких как >/2, </2, >=/2, <=/2, min/2 и max/2. Например:
~D[2017-03-31] > ~D[2017-04-01]
вернёт true, так как структурное сравнение сравнивает поле :day до :month или :year. Поэтому при сравнении структур вы часто используете функцию compare/2, предоставляемую самими модулями структур:
iex> Date.compare(~D[2017-03-31], ~D[2017-04-01]) :lt
В качестве альтернативы, вы можете использовать функции в модуле Enum для сортировки или вычисления максимума/минимума:
iex> Enum.sort([~D[2017-03-31], ~D[2017-04-01]], Date) [~D[2017-03-31], ~D[2017-04-01]] iex> Enum.max([~D[2017-03-31], ~D[2017-04-01]], Date) ~D[2017-04-01]
Истинностные и ложные значения
Помимо булевых значений true и false, в Elixir существует понятие «истинностного» или «ложного» значения.
- значение истинно, если оно ни
falseниnil - значение ложно, если оно либо
falseлибоnil
В Elixir есть функции, такие как and/2, которые работают только с булевыми значениями, но также функции, которые работают с этими истинностными/ложными значениями, такие как &&/2 и !/1.
Примеры
Мы можем проверить истинность значения, дважды используя функцию !/1.
Истинностные значения:
iex> !!true true iex> !!5 true iex> !![1,2] true iex> !!"foo" true
Ложные значения (которых ровно два):
iex> !!false false iex> !!nil false
Встраивание
Некоторые из функций, описанных в этом модуле, встроенны компилятором Elixir в их эквиваленты на Erlang в модуле :erlang. Эти функции называются BIF (встроенными внутренними функциями) на Erlang и обладают интересными свойствами, так как некоторые из них разрешены в защитных условиях, а другие используются для оптимизации компилятора.
Большинство встроенных функций можно увидеть в действии при захвате функции:
iex> &Kernel.is_atom/1 &:erlang.is_atom/1
Эти функции будут явно отмечены в документации как «встроенные компилятором».
Краткое описание
Защитники
- left != right
Оператор не равен.
- left !== right
Оператор строго не равен.
- left * right
Оператор арифметического умножения.
- +value
Унарный оператор арифметического сложения.
- left + right
Оператор арифметического сложения.
- -value
Унарный оператор арифметического вычитания.
- left - right
Оператор арифметического вычитания.
- left / right
Оператор арифметического деления.
- left < right
Оператор "меньше чем".
- left <= right
Оператор "меньше или равно".
- left == right
Оператор "равен". Возвращает
trueесли два выражения равны.- left === right
Оператор строгого равенства.
- left > right
Оператор "больше чем".
- left >= right
Оператор "больше или равно".
- abs(number)
Возвращает целое число или число с плавающей точкой, которое является абсолютным значением
number.- left and right
Оператор строгого логического "и".
- binary_part(binary, start, length)
Извлекает часть бинарного объекта, начиная с
startдлинойlength. Бинарные объекты индексируются с нуля.- bit_size(bitstring)
Возвращает целое число, представляющее размер
bitstringв битах.- byte_size(bitstring)
Возвращает количество байтов, необходимых для хранения
bitstring.- ceil(number)
Возвращает наименьшее целое число, большее или равное
number.- div(dividend, divisor)
Выполняет целочисленное деление.
- elem(tuple, index)
Возвращает элемент с нулевым
indexиндексом вtuple.- floor(number)
Возвращает наибольшее целое число, меньшее или равное
number.- hd(list)
Возвращает голову списка. Вызывает
ArgumentError, если список пуст.- left in right
Оператор принадлежности. Проверяет, является ли элемент слева членом коллекции справа.
- is_atom(term)
Возвращает
trueеслиtermэто атом; в противном случае возвращаетfalse.- is_binary(term)
Возвращает
trueеслиtermэто двоичный тип; в противном случае возвращаетfalse.- is_bitstring(term)
Возвращает
trueеслиtermэто битовая строка (включая двоичную); в противном случае возвращаетfalse.- is_boolean(term)
Возвращает
trueеслиtermэто атомtrueили атомfalse(т.е. булево значение); в противном случае возвращаетfalse.- is_exception(term)
Возвращает true, если
termэто исключение; в противном случае возвращаетfalse.- is_exception(term, name)
Возвращает true, если
termэто исключение типаname; в противном случае возвращаетfalse.- is_float(term)
Возвращает
trueеслиtermэто число с плавающей точкой; в противном случае возвращаетfalse.- is_function(term)
Возвращает
trueеслиtermэто функция; в противном случае возвращаетfalse.- is_function(term, arity)
Возвращает
trueеслиtermэто функция, которая может быть применена сarityколичеством аргументов; в противном случае возвращаетfalse.- is_integer(term)
Возвращает
trueеслиtermэто целое число; в противном случае возвращаетfalse.- is_list(term)
Возвращает
trueеслиtermэто список с нулем или более элементами; в противном случае возвращаетfalse.- is_map(term)
Возвращает
trueеслиtermэто карта; в противном случае возвращаетfalse.- is_map_key(map, key)
Возвращает
trueеслиkeyэто ключ вmap; в противном случае возвращаетfalse.- is_nil(term)
Возвращает
trueеслиtermэтоnil;falseв противном случае.- is_number(term)
Возвращает
trueеслиtermэто целое или число с плавающей точкой; в противном случае возвращаетfalse.- is_pid(term)
Возвращает
trueеслиtermэто PID (идентификатор процесса); в противном случае возвращаетfalse.- is_port(term)
Возвращает
trueеслиtermэто идентификатор порта; в противном случае возвращаетfalse.- is_reference(term)
Возвращает
trueеслиtermэто ссылка; в противном случае возвращаетfalse.- is_struct(term)
Возвращает true, если
termэто структура; в противном случае возвращаетfalse.- is_struct(term, name)
Возвращает true, если
termэто структура типаname; в противном случае возвращаетfalse.
- is_tuple(term)
Возвращает
trueеслиtermявляется кортежем; в противном случае возвращаетfalse.- length(list)
Возвращает длину
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)
Возвращает размер кортежа.
Функции
- !value
Логический оператор "not".
- left && right
Логический оператор "and".
- base ** exponent
Оператор степени.
- left ++ right
Оператор конкатенации списков. Конкатенирует правильный список и термин, возвращая список.
- left -- right
Оператор вычитания списков. Удаляет первое вхождение элемента из левого списка для каждого элемента справа.
- first..last
Создаёт диапазон от
firstдоlast.- first..last//step
Создаёт диапазон от
firstдоlastс шагомstep.- left <> right
Бинарный оператор конкатенации. Конкатенирует два двоичных числа.
- left =~ right
Оператор совпадения по тексту. Сопоставляет термин слева с регулярным выражением или строкой справа.
- @expr
Унарный оператор атрибута модуля.
- alias!(alias)
Когда используется внутри цитирования, отмечает, что указанный псевдоним не должен быть санизирован. Это означает, что псевдоним будет расширен при расширении макроса.
- apply(fun, args)
Вызывает заданную анонимную функцию
funсо списком аргументовargs.- apply(module, function_name, args)
Вызывает заданную функцию из
moduleсо списком аргументовargs.- binding(context \\ nil)
Возвращает связывание для данного контекста как список ключевых слов.
- def(call, expr \\ nil)
Определяет публичную функцию с заданным именем и телом.
- defdelegate(funs, opts)
Определяет функцию, которая делегирует другой модулю.
- defexception(fields)
Определяет исключение.
- defguard(guard)
Генерирует макрос, подходящий для использования в выражениях-стражах.
- defguardp(guard)
Генерирует приватный макрос, подходящий для использования в выражениях-стражах.
- defimpl(name, opts, do_block \\ [])
Определяет реализацию для данного протокола.
- defmacro(call, expr \\ nil)
Определяет публичный макрос с заданным именем и телом.
- defmacrop(call, expr \\ nil)
Определяет приватный макрос с заданным именем и телом.
- defmodule(alias, do_block)
Определяет модуль с заданным именем и содержимым.
- defoverridable(keywords_or_behaviour)
Делает заданные определения в текущем модуле переопределяемыми.
- defp(call, expr \\ nil)
Определяет приватную функцию с заданным именем и телом.
- defprotocol(name, do_block)
Определяет протокол.
- defstruct(fields)
Определяет структуру.
- destructure(left, right)
Распаковывает два списка, присваивая каждый термин справа соответствующему термину слева.
- exit(reason)
Останавливает выполнение вызывающего процесса с указанной причиной.
- function_exported?(module, function, arity)
Возвращает
trueеслиmoduleзагружен и содержит публичнуюfunctionс заданнымarity, в противном случаеfalse.- get_and_update_in(path, fun)
Получает значение и обновляет вложенную структуру данных с помощью заданной
path.- get_and_update_in(data, keys, fun)
Получает значение и обновляет вложенную структуру.
- get_in(data, keys)
Получает значение из вложенной структуры.
- if(condition, clauses)
Предоставляет макрос
if/2.- inspect(term, opts \\ [])
Проверяет переданный аргумент в соответствии с протоколом
Inspect. Второй аргумент — список ключевых слов с опциями для управления проверкой.- macro_exported?(module, macro, arity)
Возвращает
trueеслиmoduleзагружен и содержит публичныйmacroс заданнымarity, в противном случаеfalse.- make_ref()
Возвращает почти уникальную ссылку.
- match?(pattern, expr)
Удобный макрос, который проверяет, соответствует ли правая часть (выражение) левой части (шаблону).
- max(first, second)
Возвращает наибольший из двух заданных терминов в соответствии со структурным сравнением.
- min(first, second)
Возвращает наименьший из двух заданных терминов в соответствии со структурным сравнением.
- pop_in(path)
Удаляет ключ из вложенной структуры по заданному
path.- pop_in(data, keys)
Удаляет ключ из заданной вложенной структуры.
- put_elem(tuple, index, value)
Размещает
valueпо заданному нулевомуindexвtuple.- put_in(path, value)
Размещает значение во вложенной структуре по заданному
path.- put_in(data, keys, value)
Размещает значение во вложенной структуре.
- raise(message)
Вызывает исключение.
- raise(exception, attributes)
Вызывает исключение.
- reraise(message, stacktrace)
Вызывает исключение, сохраняя предыдущий стек вызовов.
- reraise(exception, attributes, stacktrace)
Возвращает исключение, сохраняя предыдущий стек вызовов.
- send(dest, message)
Отправляет сообщение заданному
destи возвращает это сообщение.- sigil_C(term, modifiers)
Обрабатывает сигил
~Cдля списков символов.- sigil_c(term, modifiers)
Обрабатывает сигил
~cдля списков символов.- sigil_D(date_string, modifiers)
Обрабатывает сигил
~Dдля дат.- sigil_N(naive_datetime_string, modifiers)
Обрабатывает сигил
~Nдля неопределённых дат и времени.- sigil_R(term, modifiers)
Обрабатывает сигил
~Rдля регулярных выражений.- sigil_r(term, modifiers)
Обрабатывает сигил
~rдля регулярных выражений.- sigil_S(term, modifiers)
Обрабатывает сигил
~Sдля строк.- sigil_s(term, modifiers)
Обрабатывает сигил
~sдля строк.- sigil_T(time_string, modifiers)
Обрабатывает сигил
~Tдля времени.- sigil_U(datetime_string, modifiers)
Обрабатывает сигил
~Uдля создания UTCDateTime.- sigil_W(term, modifiers)
Обрабатывает сигил
~Wдля списков слов.- sigil_w(term, modifiers)
Обрабатывает сигил
~wдля списков слов.- spawn(fun)
Запускает заданную функцию и возвращает её PID.
- spawn(module, fun, args)
Запускает заданную функцию
funиз заданногоmodule, передавая ей заданныеargs, и возвращает её PID.- spawn_link(fun)
Запускает заданную функцию, связывает её с текущим процессом и возвращает её PID.
- spawn_link(module, fun, args)
Запускает заданную функцию
funиз заданногоmodule, передавая ей заданныеargs, связывает её с текущим процессом и возвращает её PID.- spawn_monitor(fun)
Запускает заданную функцию, отслеживает её и возвращает её PID и ссылку на отслеживание.
- spawn_monitor(module, fun, args)
Запускает заданный модуль и функцию, передавая заданные аргументы, отслеживает её и возвращает её PID и ссылку на отслеживание.
- struct!(struct, fields \\ [])
Аналогично
struct/2, но проверяет валидность ключей.- struct(struct, fields \\ [])
Создаёт и обновляет структуру.
- tap(value, fun)
Перенаправляет
valueв заданнуюfunи возвращает самоvalue.- then(value, fun)
Перенаправляет
valueв заданнуюfun.- throw(term)
Нелокальное возвращение из функции.
- to_charlist(term)
Преобразует заданный термин в список символов согласно протоколу
List.Chars.- to_string(term)
Преобразует аргумент в строку согласно протоколу
String.Chars.- unless(condition, clauses)
Предоставляет макрос
unless.- update_in(path, fun)
Обновляет вложенную структуру с помощью заданной
path.- update_in(data, keys, fun)
Обновляет ключ во вложенной структуре.
- use(module, opts \\ [])
Использует указанный модуль в текущем контексте.
- var!(var, context \\ nil)
Помечает, что указанная переменная не должна подвергаться гигиенизации.
- left |> right
Оператор конвейера.
- left || right
Логический оператор «или».
Операторы-сторожа
left != rightSource
@spec 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 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, если 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
left and rightSource
Оператор строгой логической "и".
Если left является false, возвращает false; в противном случае возвращает right.
Требуется, чтобы только left операнд был булевым, поскольку он выполняет короткое замыкание. Если left операнд не является булевым, возникает исключение BadBooleanError.
Разрешено в тестах-сторожах.
Примеры
iex> true and false false iex> true and "yay!" "yay!" iex> "yay!" and true ** (BadBooleanError) expected a boolean on left-side of "and", got: "yay!"
binary_part(binary, start, length)Source
@spec binary_part(binary(), non_neg_integer(), integer()) :: binary()
Извлекает часть бинарного объекта, начиная с start и длиной length. Бинарные объекты нумеруются с нуля.
Если start или length каким-либо образом выходят за пределы бинарного объекта, генерируется исключение ArgumentError.
Разрешено в тестах условий. Встраивается компилятором.
Примеры
iex> binary_part("foo", 1, 2)
"oo"
Отрицательное значение length может использоваться для извлечения байтов, которые находятся перед байтом по start:
iex> binary_part("Hello", 5, -3)
"llo"
Исключение ArgumentError генерируется, когда длина выходит за пределы бинарного объекта:
binary_part("Hello", 0, 10)
** (ArgumentError) argument error bit_size(bitstring)Source
@spec bit_size(bitstring()) :: non_neg_integer()
Возвращает целое число, которое представляет размер bitstring в битах.
Разрешено в тестах условий. Встраивается компилятором.
Примеры
iex> bit_size(<<433::16, 3::3>>) 19 iex> bit_size(<<1, 2, 3>>) 24
byte_size(bitstring)Source
@spec byte_size(bitstring()) :: non_neg_integer()
Возвращает количество байтов, необходимых для размещения bitstring.
То есть, если количество битов в bitstring не делится на 8, результирующее количество байтов будет округлено вверх (в большую сторону). Эта операция выполняется за постоянное время.
Разрешено в тестах условий. Встраивается компилятором.
Примеры
iex> byte_size(<<433::16, 3::3>>) 3 iex> byte_size(<<1, 2, 3>>) 3
ceil(number)Source
@spec ceil(number()) :: integer()
Возвращает наименьшее целое число, большее или равное number.
Если требуется выполнить операцию ceil для других десятичных знаков, используйте Float.ceil/2.
Разрешено в тестах условий. Встраивается компилятором.
div(dividend, divisor)Source
@spec div(integer(), neg_integer() | pos_integer()) :: integer()
Выполняет целочисленное деление.
Генерирует исключение ArithmeticError, если один из аргументов не является целым числом или когда divisor равно 0.
div/2 выполняет обрезанное целочисленное деление. Это означает, что результат всегда округляется к нулю.
Если нужно выполнить целочисленное деление с округлением к ближайшему меньшему целому числу (к отрицательной бесконечности), используйте Integer.floor_div/2.
Разрешено в тестах условий. Встраивается компилятором.
Примеры
div(5, 2) #=> 2 div(6, -4) #=> -1 div(-99, 2) #=> -49 div(100, 0) ** (ArithmeticError) bad argument in arithmetic expression
elem(tuple, index)Source
@spec elem(tuple(), non_neg_integer()) :: term()
Получает элемент по нулево-базовому index в tuple.
Генерирует ArgumentError, если индекс отрицательный или выходит за пределы кортежа.
Разрешено в тестах условий. Встраивается компилятором.
Примеры
tuple = {:foo, :bar, 3}
elem(tuple, 1)
#=> :bar
elem({}, 0)
** (ArgumentError) argument error
elem({:foo, :bar}, 2)
** (ArgumentError) argument error floor(number)Source
@spec floor(number()) :: integer()
Возвращает наибольшее целое число, меньшее или равное number.
Если требуется выполнить операцию floor для других десятичных знаков, используйте Float.floor/2.
Разрешено в тестах условий. Встраивается компилятором.
hd(list)Source
@spec hd(nonempty_maybe_improper_list(elem, any())) :: elem when elem: term()
Возвращает голову списка. Генерирует ArgumentError, если список пустой.
Работает со списками неправильной структуры.
Разрешено в тестах условий. Встраивается компилятором.
Примеры
hd([1, 2, 3, 4]) #=> 1 hd([1 | 2]) #=> 1
При передаче пустого списка генерируется:
hd([]) #=> ** (ArgumentError) argument error
left in rightSource
Оператор членства. Проверяет, является ли элемент слева членом коллекции справа.
Примеры
iex> x = 1 iex> x in [1, 2, 3] true
Этот оператор (который является макросом) просто преобразуется в вызов Enum.member?/2. Приведённый выше пример преобразуется в:
Enum.member?([1, 2, 3], x)
Elixir также поддерживает left not in right, что эквивалентно not(left in right):
iex> x = 1 iex> x not in [1, 2, 3] false
Условия
Оператор in/2 (а также not in) может использоваться в условиях, если правая часть является диапазоном или списком. В таких случаях Elixir расширит оператор до корректного выражения условия. Например:
when x in [1, 2, 3]
что преобразуется в:
when x === 1 or x === 2 or x === 3
Однако, такая конструкция будет неэффективной для больших списков. В таких случаях лучше отказаться от использования условий и использовать более подходящую структуру данных, такую как MapSet.
Учёт AST
left not in right разбирается компилятором в AST:
{:not, _, [{:in, _, [left, right]}]}
Это тот же AST, что и not(left in right).
Кроме того, Macro.to_string/2 и Code.format_string!/2 преобразуют все вхождения этого AST в left not in right.
is_atom(term)Source
@spec is_atom(term()) :: boolean()
Возвращает true, если term является атомом; в противном случае возвращает false.
Разрешено в тестах условий. Встраивается компилятором.
Примеры
iex> is_atom(false)
true
iex> is_atom(:name)
true
iex> is_atom(AnAtom)
true
iex> is_atom("true")
false is_binary(term)Source
@spec is_binary(term()) :: boolean()
Возвращает true, если term является бинарным объектом; в противном случае возвращает false.
Бинарный объект всегда содержит целое число байтов.
Разрешено в тестах условий. Встраивается компилятором.
Примеры
iex> is_binary("foo")
true
iex> is_binary(<<1::3>>)
false is_bitstring(term)Source
@spec is_bitstring(term()) :: boolean()
Возвращает true, если term является битовой строкой (включая бинарный объект); в противном случае возвращает false.
Разрешено в тестах условий. Встраивается компилятором.
Примеры
iex> is_bitstring("foo")
true
iex> is_bitstring(<<1::3>>)
true is_boolean(term)Source
@spec is_boolean(term()) :: boolean()
Возвращает true, если term является либо атомом true, либо атомом false, (т.е. логическое значение); в противном случае возвращает false.
Разрешено в тестах условий. Встраивается компилятором.
Примеры
iex> is_boolean(false) true iex> is_boolean(true) true iex> is_boolean(:test) false
is_exception(term)Source
Возвращает true, если term является исключением; в противном случае возвращает false.
Разрешено в тестах условий.
Примеры
iex> is_exception(%RuntimeError{})
true
iex> is_exception(%{})
false is_exception(term, name)Source
Возвращает true, если term является исключением типа name; в противном случае возвращает false.
Разрешено в тестах условий.
Примеры
iex> is_exception(%RuntimeError{}, RuntimeError)
true
iex> is_exception(%RuntimeError{}, Macro.Env)
false is_float(term)Source
@spec is_float(term()) :: boolean()
Возвращает true, если term является числом с плавающей точкой; в противном случае возвращает false.
Допускается в тестах условий. Встраивается компилятором.
is_function(term)Source
@spec is_function(term()) :: boolean()
Возвращает true, если term является функцией; в противном случае возвращает false.
Допускается в тестах условий. Встраивается компилятором.
Примеры
iex> is_function(fn x -> x + x end)
true
iex> is_function("not a function")
false is_function(term, arity)Source
@spec is_function(term(), non_neg_integer()) :: boolean()
Возвращает true, если term является функцией, к которой можно применить arity аргументов; в противном случае возвращает false.
Допускается в тестах условий. Встраивается компилятором.
Примеры
iex> is_function(fn x -> x * 2 end, 1) true iex> is_function(fn x -> x * 2 end, 2) false
is_integer(term)Source
@spec is_integer(term()) :: boolean()
Возвращает true, если term является целым числом; в противном случае возвращает false.
Допускается в тестах условий. Встраивается компилятором.
is_list(term)Source
@spec is_list(term()) :: boolean()
Возвращает true, если term является списком с нулем или более элементами; в противном случае возвращает false.
Допускается в тестах условий. Встраивается компилятором.
is_map(term)Source
@spec is_map(term()) :: boolean()
Возвращает true, если term является картой; в противном случае возвращает false.
Допускается в тестах условий. Встраивается компилятором.
is_map_key(map, key)Source
@spec is_map_key(map(), term()) :: boolean()
Возвращает true, если key является ключом в map; в противном случае возвращает false.
Вызывает BadMapError, если первый элемент не является картой.
Допускается в тестах условий. Встраивается компилятором.
is_nil(term)Source
Возвращает true, если term является nil, false в противном случае.
Допускается в условиях.
Примеры
iex> is_nil(1) false iex> is_nil(nil) true
is_number(term)Source
@spec is_number(term()) :: boolean()
Возвращает true, если term является целым числом или числом с плавающей точкой; в противном случае возвращает false.
Допускается в тестах условий. Встраивается компилятором.
is_pid(term)Source
@spec is_pid(term()) :: boolean()
Возвращает true, если term является идентификатором процесса (PID); в противном случае возвращает false.
Допускается в тестах условий. Встраивается компилятором.
is_port(term)Source
@spec is_port(term()) :: boolean()
Возвращает true, если term является идентификатором порта; в противном случае возвращает false.
Допускается в тестах условий. Встраивается компилятором.
is_reference(term)Source
@spec is_reference(term()) :: boolean()
Возвращает true, если term является ссылкой; в противном случае возвращает false.
Допускается в тестах условий. Встраивается компилятором.
is_struct(term)Source
Возвращает true, если term является структурой; в противном случае возвращает false.
Допускается в тестах условий.
Примеры
iex> is_struct(URI.parse("/"))
true
iex> is_struct(%{})
false is_struct(term, name)Source
Возвращает true, если term является структурой name; в противном случае возвращает false.
Допускается в тестах условий.
Примеры
iex> is_struct(URI.parse("/"), URI)
true
iex> is_struct(URI.parse("/"), Macro.Env)
false is_tuple(term)Source
@spec is_tuple(term()) :: boolean()
Возвращает true, если term является кортежем; в противном случае возвращает false.
Допускается в тестах условий. Встраивается компилятором.
length(list)Source
@spec length(list()) :: non_neg_integer()
Возвращает длину list.
Допускается в тестах условий. Встраивается компилятором.
Примеры
iex> length([1, 2, 3, 4, 5, 6, 7, 8, 9]) 9
map_size(map)Source
@spec map_size(map()) :: non_neg_integer()
Возвращает размер карты.
Размер карты — это количество пар «ключ-значение», которые содержит карта.
Эта операция выполняется за постоянное время.
Допускается в тестах условий. Встраивается компилятором.
Примеры
iex> map_size(%{a: "foo", b: "bar"})
2 node()Source
@spec node() :: node()
Возвращает атом, представляющий имя локального узла. Если узел не активен, вместо этого возвращается :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(делимое, делитель)Source
@spec rem(integer(), neg_integer() | pos_integer()) :: integer()
Вычисляет остаток от деления целых чисел.
rem/2 использует усеченное деление, что означает, что результат всегда будет иметь знак dividend.
Вызывает исключение ArithmeticError, если один из аргументов не является целым числом или когда divisor является 0.
Разрешено в тестах охранных условий. Компилятор выполняет встраивание.
Примеры
iex> rem(5, 2) 1 iex> rem(6, -4) 2
round(число)Source
@spec round(number()) :: integer()
Округляет число до ближайшего целого.
Если число равноудалено от двух ближайших целых чисел, округляет в сторону от нуля.
Разрешено в тестах охранных условий. Компилятор выполняет встраивание.
Примеры
iex> round(5.6) 6 iex> round(5.2) 5 iex> round(-9.9) -10 iex> round(-9) -9 iex> round(2.5) 3 iex> round(-2.5) -3
self()Source
@spec self() :: pid()
Возвращает PID (идентификатор процесса) вызывающего процесса.
Разрешено в охранных условиях. Компилятор выполняет встраивание.
tl(список)Source
@spec tl(nonempty_maybe_improper_list(elem, tail)) :: maybe_improper_list(elem, tail) | tail when elem: term(), tail: term()
Возвращает хвост списка. Вызывает ArgumentError, если список пустой.
Работает со списками нестандартной формы.
Разрешено в тестах охранных условий. Компилятор выполняет встраивание.
Примеры
tl([1, 2, 3, :go])
#=> [2, 3, :go]
tl([:one])
#=> []
tl([:a, :b | :c])
#=> [:b | :c]
tl([:a | %{b: 1}])
#=> %{b: 1}
При передаче пустого списка возникает:
tl([]) #=> ** (ArgumentError) argument error
trunc(число)Source
@spec trunc(number()) :: integer()
Возвращает целую часть number.
Разрешено в тестах охранных условий. Компилятор выполняет встраивание.
Примеры
iex> trunc(5.4) 5 iex> trunc(-5.99) -5 iex> trunc(-5) -5
tuple_size(кортеж)Source
@spec tuple_size(tuple()) :: non_neg_integer()
Возвращает размер кортежа.
Эта операция выполняется за постоянное время.
Разрешено в тестах охранных условий. Компилятор выполняет встраивание.
Примеры
iex> tuple_size({:a, :b, :c})
3 Функции
!valueSource
Оператор логического "не".
Принимает любое значение (не только булевы) и возвращает true если value является false или nil; в противном случае возвращает false.
Запрещено в операторах-условиях.
Примеры
iex> !Enum.empty?([]) false iex> !List.first([]) true
left && rightSource
Оператор логического "и".
Представляет собой оператор короткого замыкания, который вычисляет и возвращает второе выражение только если первое выражение вычисляется как истинное значение (не false и не nil). В противном случае возвращается первое выражение.
Запрещено в операторах-условиях.
Примеры
iex> Enum.empty?([]) && Enum.empty?([]) true iex> List.first([]) && true nil iex> Enum.empty?([]) && List.first([1]) 1 iex> false && throw(:bad) false
Обратите внимание, что в отличие от and/2, этот оператор принимает любое выражение в качестве первого аргумента, а не только булевы значения.
base ** exponentSource
@spec integer() ** non_neg_integer() :: integer()
@spec integer() ** neg_integer() :: float()
@spec float() ** float() :: float()
Оператор возведения в степень.
Ожидает два числовых аргумента. Если левая часть — целое число, а правая — неотрицательное число, то результат — целое число. В противном случае возвращается число с плавающей точкой.
Примеры
iex> 2 ** 2 4 iex> 2 ** -4 0.0625 iex> 2.0 ** 2 4.0 iex> 2 ** 2.0 4.0
left ++ rightSource
@spec list() ++ term() :: maybe_improper_list()
Оператор конкатенации списков. Конкатенирует правильный список и элемент, возвращая список.
Сложность a ++ b пропорциональна length(a), поэтому избегайте многократного добавления элементов в списки произвольной длины, например, list ++ [element]. Вместо этого рассмотрите возможность вставки в начало с помощью [element | rest] и последующего обращения.
Если операнд right не является правильным списком, возвращается неправильный список. Если операнд left не является правильным списком, генерируется исключение ArgumentError.
Встроен в компилятор.
Примеры
iex> [1] ++ [2, 3] [1, 2, 3] iex> 'foo' ++ 'bar' 'foobar' # returns an improper list iex> [1] ++ 2 [1 | 2] # returns a proper list iex> [1] ++ [2] [1, 2] # improper list on the right will return an improper list iex> [1] ++ [2 | 3] [1, 2 | 3]
left -- rightSource
@spec list() -- list() :: list()
Оператор вычитания списков. Удаляет первое вхождение элемента в левом списке для каждого элемента в правом.
Функция оптимизирована, поэтому сложность a -- b пропорциональна length(a) * log(length(b)). См. также Руководство по производительности Erlang.
Встроен в компилятор.
Примеры
iex> [1, 2, 3] -- [1, 2] [3] iex> [1, 2, 3, 2, 1] -- [1, 2, 2] [3, 1]
Оператор --/2 ассоциативен справа, что означает:
iex> [1, 2, 3] -- [2] -- [3] [1, 3]
Что эквивалентно:
iex> [1, 2, 3] -- ([2] -- [3]) [1, 3]
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) []
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()
Оператор совпадения текста. Сопоставляет терм в левой части с регулярным выражением или строкой в правой части.
Если right является регулярным выражением, возвращает true если left соответствует right.
Если right является строкой, возвращает true если left содержит right.
Примеры
iex> "abcd" =~ ~r/c(d)/ true iex> "abcd" =~ ~r/e/ false iex> "abcd" =~ ~r// true iex> "abcd" =~ "bc" true iex> "abcd" =~ "ad" false iex> "abcd" =~ "abcd" true iex> "abcd" =~ "" true
Для получения дополнительной информации о регулярных выражениях, обратитесь к модулю Regex.
@exprSource
Унарный оператор атрибута модуля.
Читает и записывает атрибуты в текущем модуле.
Классический пример атрибутов — помечать, что модуль реализует поведение OTP, например, GenServer:
defmodule MyServer do @behaviour GenServer # ... callbacks ... end
По умолчанию Elixir поддерживает все атрибуты модулей, поддерживаемые Erlang, но также можно использовать пользовательские атрибуты:
defmodule MyServer do @my_data 13 IO.inspect(@my_data) #=> 13 end
В отличие от Erlang, такие атрибуты по умолчанию не хранятся в модуле, так как в Elixir часто используются пользовательские атрибуты для хранения временных данных, которые будут доступны на этапе компиляции. Пользовательские атрибуты можно настроить на более близкое поведение Erlang, используя Module.register_attribute/3.
Важно: Библиотеки и фреймворки должны использовать префикс подчёркивания для любых частных атрибутов модулей, таких как
@_my_data, чтобы инструменты автодополнения не отображали их в предложениях и подсказках.
И, наконец, обратите внимание, что атрибуты также можно читать внутри функций:
defmodule MyServer do @my_data 11 def first_data, do: @my_data @my_data 13 def second_data, do: @my_data end MyServer.first_data() #=> 11 MyServer.second_data() #=> 13
Важно отметить, что чтение атрибута создаёт моментальную копию текущего значения. Другими словами, значение считывается на этапе компиляции, а не на этапе выполнения. Обратитесь к модулю Module для получения других функций управления атрибутами модулей.
Внимание! Множественные ссылки на один и тот же атрибут
Как упоминалось выше, каждый раз при чтении атрибута модуля создаётся моментальная копия его текущего значения. Поэтому, если вы храните большие значения в атрибутах модуля (например, встраиваете внешние файлы в атрибуты модуля), следует избегать множественных ссылок на один и тот же атрибут. Например, не делайте так:
@files %{
example1: File.read!("lib/example1.data"),
example2: File.read!("lib/example2.data")
}
def example1, do: @files[:example1]
def example2, do: @files[:example2]
В приведённом примере каждая ссылка на @files может привести к полной и отдельной копии всего атрибута модуля @files. Вместо этого используйте ссылку на атрибут модуля один раз в частной функции:
@files %{
example1: File.read!("lib/example1.data"),
example2: File.read!("lib/example2.data")
}
defp files(), do: @files
def example1, do: files()[:example1]
def example2, do: files()[:example2]
Внимание! Зависимости от времени компиляции
Помните, что ссылки на другие модули, даже в атрибутах модулей, создают зависимости от времени компиляции для этих модулей.
Например, рассмотрите этот распространённый паттерн:
@values [:foo, :bar, :baz] def handle_arg(arg) when arg in @values do ... end
Хотя приведенное выше верно, представьте, что вместо этого у вас есть фактические имена модулей в атрибуте модуля, как в этом примере:
@values [Foo, Bar, Baz] def handle_arg(arg) when arg in @values do ... end
В приведенном коде будет определена зависимость от времени компиляции от модулей Foo, Bar, и Baz, что означает, что если любой из них изменится, текущему модулю потребуется перекомпиляция. В таких случаях может быть предпочтительнее вовсе обойтись без атрибута модуля:
def handle_arg(arg) when arg in [Foo, Bar, Baz] do ... end
alias!(alias)Source
Когда используется внутри цитирования, отмечает, что данный псевдоним не должен быть подвергнут санизации. Это означает, что псевдоним будет раскрыт при раскрытии макроса.
См. Kernel.SpecialForms.quote/2 для получения дополнительной информации.
apply(fun, args)Source
@spec apply((... -> any()), [any()]) :: any()
Вызывает заданную анонимную функцию fun со списком аргументов args.
Если количество аргументов известно на этапе компиляции, предпочтительнее использовать fun.(arg_1, arg_2, ..., arg_n), так как оно более наглядно, чем apply(fun, [arg_1, arg_2, ..., arg_n]).
Встроен в компилятор.
Примеры
iex> apply(fn x -> x * 2 end, [2]) 4
apply(module, function_name, args)Source
@spec apply(module(), function_name :: atom(), [any()]) :: any()
Вызывает заданную функцию из module со списком аргументов args.
apply/3 используется для вызова функций, где модуль, имя функции или аргументы определены динамически во время выполнения. По этой причине вы не можете вызывать макросы с помощью apply/3, только функции.
Если количество аргументов и имя функции известны на этапе компиляции, предпочтительнее использовать module.function(arg_1, arg_2, ..., arg_n) , так как оно более понятно, чем apply(module, :function, [arg_1, arg_2, ..., arg_n]).
apply/3 нельзя использовать для вызова приватных функций.
Встроенный компилятором.
Примеры
iex> apply(Enum, :reverse, [[1, 2, 3]]) [3, 2, 1]
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]
def(call, expr \\ nil)Source
Определяет публичную функцию с данным именем и телом.
Примеры
defmodule Foo do def bar, do: :baz end Foo.bar() #=> :baz
Функция, ожидающая аргументы, может быть определена следующим образом:
defmodule Foo do
def sum(a, b) do
a + b
end
end
В приведенном примере определена sum/2 функция; эта функция получает два аргумента и возвращает их сумму.
Аргументы по умолчанию
\\ используется для указания значения по умолчанию для параметра функции. Например:
defmodule MyMath do
def multiply_by(number, factor \\ 2) do
number * factor
end
end
MyMath.multiply_by(4, 3)
#=> 12
MyMath.multiply_by(4)
#=> 8
Компилятор преобразует это в несколько функций с разными арностью, например MyMath.multiply_by/1 и MyMath.multiply_by/2, которые представляют случаи, когда аргументы для параметров с значениями по умолчанию передаются или не передаются.
При определении функции с аргументами по умолчанию и несколькими явно объявленными разделами необходимо написать заголовок функции, который объявляет значения по умолчанию. Например:
defmodule MyString do
def join(string1, string2 \\ nil, separator \\ " ")
def join(string1, nil, _separator) do
string1
end
def join(string1, string2, separator) do
string1 <> separator <> string2
end
end
Обратите внимание, что \\ нельзя использовать с анонимными функциями, поскольку они могут иметь только одну арность.
Списки ключевых слов с аргументами по умолчанию
Функции, содержащие много аргументов, могут извлечь выгоду из использования списков Keyword для группировки и передачи атрибутов как единого значения.
defmodule MyConfiguration do
@default_opts [storage: "local"]
def configure(resource, opts \\ []) do
opts = Keyword.merge(@default_opts, opts)
storage = opts[:storage]
# ...
end
end
Разница между использованием Map и Keyword для хранения многих аргументов заключается в ключах Keyword:
- должны быть атомами
- могут быть заданы более одного раза
- упорядочены, как указано разработчиком
Имена функций и переменных
Имена функций и переменных имеют следующий синтаксис: строчная буква ASCII или подчеркивание, за которыми следуют любое количество строчных или прописных букв ASCII, цифр или подчеркиваний. Дополнительно они могут заканчиваться либо знаком восклицания, либо знаком вопроса.
Для переменных любой идентификатор, начинающийся с подчеркивания, должен указывать на неиспользуемую переменную. Например:
def foo(bar) do [] end #=> warning: variable bar is unused def foo(_bar) do [] end #=> no warning def foo(_bar) do _bar end #=> warning: the underscored variable "_bar" is used after being set
rescue/catch/after/else
Тела функций поддерживают rescue, catch, after, и else как Kernel.SpecialForms.try/1 (известные как «явный try»). Например, следующие две функции эквивалентны:
def convert(number) do
try do
String.to_integer(number)
rescue
e in ArgumentError -> {:error, e.message}
end
end
def convert(number) do
String.to_integer(number)
rescue
e in ArgumentError -> {:error, e.message}
end defdelegate(funs, opts)Source
Определяет функцию, которая делегирует другую модуль.
Функции, определенные с помощью defdelegate/2, являются публичными и могут быть вызваны извне модуля, в котором они определены, как если бы они были определены с помощью def/2. Таким образом, defdelegate/2 о расширении публичного API текущего модуля. Если нужно вызвать функцию, определенную в другом модуле, не используя его полное имя модуля, используйте alias/2 для сокращения имени модуля или import/2 для возможности вызова функции без имени модуля.
Делегирование работает только с функциями; делегирование макросов не поддерживается.
См. def/2 для правил именования и аргументов по умолчанию.
Параметры
:to- модуль, которому передается вызов.:as- функция для вызова на целевом модуле, указанном в:to. Этот параметр является необязательным и по умолчанию равен имени делегируемой функции (funs).
Примеры
defmodule MyList do defdelegate reverse(list), to: Enum defdelegate other_reverse(list), to: Enum, as: :reverse end MyList.reverse([1, 2, 3]) #=> [3, 2, 1] MyList.other_reverse([1, 2, 3]) #=> [3, 2, 1]
defexception(fields)Source
Определяет исключение.
Исключения — это структуры, основанные на модуле, который реализует поведение Exception. Поведение Exception требует реализации двух функций:
exception/1— получает аргументы, переданные вraise/2, и возвращает структуру исключения. По умолчанию реализация принимает либо набор аргументов ключевых слов, которые объединяются в структуру, либо строку, используемую в качестве сообщения исключения.message/1— получает структуру исключения и должна вернуть его сообщение. Чаще всего исключения имеют поле сообщения, которое по умолчанию доступно в этой функции. Однако, если исключение не имеет поля сообщения, эта функция должна быть реализована явно.
Поскольку исключения являются структурами, доступен также API, поддерживаемый defstruct/1, в defexception/1.
Выбрасывание исключений
Наиболее распространенный способ выбросить исключение — через raise/2:
defmodule MyAppError do
defexception [:message]
end
value = [:hello]
raise MyAppError,
message: "did not get what was expected, got: #{inspect(value)}"
Во многих случаях удобнее передавать ожидаемое значение в raise/2 и генерировать сообщение в обратном вызове Exception.exception/1:
defmodule MyAppError do
defexception [:message]
@impl true
def exception(value) do
msg = "did not get what was expected, got: #{inspect(value)}"
%MyAppError{message: msg}
end
end
raise MyAppError, value
Приведенный пример демонстрирует предпочтительную стратегию для настройки сообщений об ошибках.
defguard(guard)Source
@spec defguard(Macro.t()) :: Macro.t()
Генерирует макрос, подходящий для использования в выражениях охраны.
Вызывает ошибку на этапе компиляции, если определение использует выражения, недопустимые в охранах, и в противном случае создает макрос, который может использоваться как внутри, так и вне охраны.
Обратите внимание, что в Elixir принято называть функции/макросы, разрешенные в охранах, префиксом is_, например is_list/1. Однако, если функция/макрос возвращает логическое значение и не разрешен в охранах, он не должен иметь префикс и должен заканчиваться знаком вопроса, например Keyword.keyword?/1.
Пример
defmodule Integer.Guards do
defguard is_even(value) when is_integer(value) and rem(value, 2) == 0
end
defmodule Collatz do
@moduledoc "Tools for working with the Collatz sequence."
import Integer.Guards
@doc "Determines the number of steps `n` takes to reach `1`."
# If this function never converges, please let me know what `n` you used.
def converge(n) when n > 0, do: step(n, 0)
defp step(1, step_count) do
step_count
end
defp step(n, step_count) when is_even(n) do
step(div(n, 2), step_count + 1)
end
defp step(n, step_count) do
step(3 * n + 1, step_count + 1)
end
end defguardp(guard)Source
@spec defguardp(Macro.t()) :: Macro.t()
Генерирует приватный макрос, подходящий для использования в выражениях охраны.
Вызывает ошибку на этапе компиляции, если определение использует выражения, недопустимые в охранах, и в противном случае создает приватный макрос, который может использоваться как внутри, так и вне охраны в текущем модуле.
Аналогично defmacrop/2, defguardp/1 должен быть определён до использования в текущем модуле.
defimpl(name, opts, do_block \\ [])Source
Определяет реализацию для данного протокола.
См. модуль Protocol для получения дополнительной информации.
defmacro(call, expr \\ nil)Source
Определяет публичный макрос с данным именем и телом.
Макросы должны быть определены перед использованием.
См. def/2 для правил именования и аргументов по умолчанию.
Примеры
defmodule MyLogic do
defmacro unless(expr, opts) do
quote do
if !unquote(expr), unquote(opts)
end
end
end
require MyLogic
MyLogic.unless false do
IO.puts("It works")
end defmacrop(call, expr \\ nil)Source
Определяет приватную макрос с данным именем и телом.
Приватные макросы доступны только из того же модуля, в котором они определены.
Приватные макросы должны быть определены до их использования.
См. defmacro/2 для получения дополнительной информации, и см. def/2 для правил именования и аргументов по умолчанию.
defmodule(alias, do_block)Source
Определяет модуль по имени с заданным содержимым.
Эта макрос определяет модуль с данным alias в качестве имени и с заданным содержимым. Возвращает кортеж из четырёх элементов:
:module- имя модуля
- бинарное содержимое модуля
- результат выполнения блока содержимого
Примеры
defmodule Number do
def one, do: 1
def two, do: 2
end
#=> {:module, Number, <<70, 79, 82, ...>>, {:two, 0}}
Number.one()
#=> 1
Number.two()
#=> 2
Вложенность
Вложенность модуля внутри другого модуля влияет на имя вложенного модуля:
defmodule Foo do defmodule Bar do end end
В примере выше создаются два модуля - Foo и Foo.Bar. При вложенности Elixir автоматически создаёт псевдоним для внутреннего модуля, позволяя обращаться ко второму модулю Foo.Bar как к Bar в том же лексическом контексте, где он определён (модуль Foo). Это происходит только в том случае, если вложенный модуль определяется через псевдоним.
Если модуль Foo.Bar будет перемещён в другое место, ссылки на Bar в модуле Foo нужно будет обновить на полное квалифицированное имя (Foo.Bar) или псевдоним нужно будет явно установить в модуле Foo с помощью Kernel.SpecialForms.alias/2.
defmodule Foo.Bar do # code end defmodule Foo do alias Foo.Bar # code here can refer to "Foo.Bar" as just "Bar" end
Динамические имена
Имена модулей Elixir могут быть динамически сгенерированы. Это очень полезно при работе с макросами. Например, можно написать:
defmodule String.to_atom("Foo#{1}") do
# contents ...
end
Elixir примет любое имя модуля, при условии, что выражение, переданное в качестве первого аргумента defmodule/2, оценивается как атом. Обратите внимание, что при использовании динамического имени Elixir не будет вкладывать имя в текущий модуль и не будет автоматически устанавливать псевдоним.
Зарезервированные имена модулей
Если вы попытаетесь определить модуль, который уже существует, вы получите предупреждение о том, что модуль был переопределён.
Есть некоторые модули, которые Elixir пока не реализует, но может реализовать в будущем. Эти модули зарезервированы, и их определение приведёт к ошибке компиляции:
defmodule Any do # code end ** (CompileError) iex:1: module Any is reserved and cannot be defined
Elixir зарезервировал следующие имена модулей: Elixir, Any, BitString, PID, и Reference.
defoverridable(keywords_or_behaviour)Source
Делает данные определения в текущем модуле переопределяемыми.
Если пользователь определяет новую функцию или макрос с тем же именем и арностью, то переопределяемые определения отбрасываются. В противном случае используются исходные определения.
Возможно, что переопределённое определение будет иметь другую видимость, чем исходное: публичная функция может быть переопределена приватной функцией и наоборот.
Макросы не могут быть переопределены как функции и наоборот.
Пример
defmodule DefaultMod do
defmacro __using__(_opts) do
quote do
def test(x, y) do
x + y
end
defoverridable test: 2
end
end
end
defmodule InheritMod do
use DefaultMod
def test(x, y) do
x * y + super(x, y)
end
end
Как показано в примере выше, super может быть использован для вызова реализации по умолчанию.
Если @behaviour было определено, defoverridable также может быть вызван с модулем в качестве аргумента. Все реализованные обратные вызовы из поведения выше вызова defoverridable будут помечены как переопределяемые.
Пример
defmodule Behaviour do
@callback foo :: any
end
defmodule DefaultMod do
defmacro __using__(_opts) do
quote do
@behaviour Behaviour
def foo do
"Override me"
end
defoverridable Behaviour
end
end
end
defmodule InheritMod do
use DefaultMod
def foo do
"Overridden"
end
end defp(call, expr \\ nil)Source
Определяет приватную функцию с данным именем и телом.
Приватные функции доступны только изнутри модуля, в котором они определены. Попытка доступа к приватной функции извне модуля, в котором она определена, приводит к исключению UndefinedFunctionError.
См. def/2 для получения дополнительной информации.
Примеры
defmodule Foo do
def bar do
sum(1, 2)
end
defp sum(a, b), do: a + b
end
Foo.bar()
#=> 3
Foo.sum(1, 2)
** (UndefinedFunctionError) undefined function Foo.sum/2 defprotocol(name, do_block)Source
Определяет протокол.
См. модуль Protocol для получения дополнительной информации.
defstruct(fields)Source
Определяет структуру.
Структура — это помеченное отображение, которое позволяет разработчикам задавать значения по умолчанию для ключей, теги для использования в полиморфных диспетчерах и проверках на этапе компиляции. Для получения дополнительной информации о структурах см. Kernel.SpecialForms.%/2.
Определение структуры возможно только в пределах одного модуля, так как структура связана с самим модулем. Вызов defstruct/1 также определяет функцию __struct__/0, которая возвращает саму структуру.
Примеры
defmodule User do defstruct name: nil, age: nil end
Поля структуры вычисляются на этапе компиляции, что позволяет им быть динамическими. В примере ниже, 10 + 11 вычисляется на этапе компиляции, и поле age хранит значение 21:
defmodule User do defstruct name: nil, age: 10 + 11 end
Аргумент fields обычно представляет собой список ключевых слов со строчными ключами, такими как имена полей, и соответствующими значениями по умолчанию. defstruct/1 также поддерживает список атомов в качестве аргумента: в этом случае атомы в списке будут использоваться в качестве имён полей структуры, и все они будут иметь значение по умолчанию nil.
defmodule Post do defstruct [:title, :content, :author] end
Наследование
Хотя структуры являются отображениями, по умолчанию структуры не реализуют ни один из протоколов, реализованных для отображений. Например, попытка использования протокола со структурой User приводит к ошибке:
john = %User{name: "John"}
MyProtocol.call(john)
** (Protocol.UndefinedError) protocol MyProtocol not implemented for %User{...}
defstruct/1, однако, позволяет реализовывать протоколы наследуя их. Это можно сделать, определив атрибут @derive как список перед вызовом defstruct/1:
defmodule User do @derive [MyProtocol] defstruct name: nil, age: 10 + 11 end MyProtocol.call(john) # it works!
Для каждого протокола в списке @derive Elixir проверит, реализован ли протокол для Any. Если реализация протокола Any определяет обратный вызов __deriving__/3, обратный вызов будет вызван, и он должен определить реализующий модуль. В противном случае реализация, которая просто указывает на реализацию Any автоматически наследуется. Для получения дополнительной информации об обратном вызове __deriving__/3 см. Protocol.derive/3.
Принудительное использование ключей
При создании структуры Elixir автоматически гарантирует, что все ключи принадлежат структуре:
%User{name: "john", unknown: :key}
** (KeyError) key :unknown not found in: %User{age: 21, name: nil}
Elixir также позволяет разработчикам принудительно указывать, что при создании структуры определённые ключи должны всегда предоставляться:
defmodule User do @enforce_keys [:name] defstruct name: nil, age: 10 + 11 end
Теперь попытка создания структуры без ключа name завершится ошибкой:
%User{age: 21}
** (ArgumentError) the following keys must also be given when building struct User: [:name]
Обратите внимание, что @enforce_keys — это просто гарантия на этапе компиляции, помогающая разработчикам при создании структур. Она не применяется при обновлении и не предоставляет никакой валидации значений.
Типы
Рекомендуется определять типы для структур. По соглашению такой тип называется t. Чтобы определить структуру внутри типа, используется синтаксис литерала структуры:
defmodule User do
defstruct name: "John", age: 25
@type t :: %__MODULE__{name: String.t(), age: non_neg_integer}
end
Рекомендуется использовать синтаксис структуры только при определении типа структуры. При ссылке на другую структуру лучше использовать User.t вместо %User{}.
Типы полей структуры, которые не включены в %User{}, по умолчанию равны term() (см. term/0).
Структуры, внутренняя структура которых приватна для локального модуля (сопоставление с образцом или прямой доступ к полям которых недопустим), должны использовать атрибут @opaque. Структуры, внутренняя структура которых публична, должны использовать атрибут @type.
destructure(left, right)Source
Распаковывает два списка, присваивая каждый элемент правого списка соответствующему элементу левого списка.
В отличие от сопоставления с образцом с помощью =, если размеры левого и правого списков не совпадают, распаковка просто останавливается вместо выдачи ошибки.
Примеры
iex> destructure([x, y, z], [1, 2, 3, 4, 5])
iex> {x, y, z}
{1, 2, 3}
В примере выше, даже если правый список имеет больше элементов, чем левый, распаковка работает нормально. Если правый список меньше, оставшиеся элементы просто устанавливаются в nil:
iex> destructure([x, y, z], [1])
iex> {x, y, z}
{1, nil, nil}
Левая часть поддерживает любое выражение, которое вы бы использовали в левой части сопоставления:
x = 1 destructure([^x, y, z], [1, 2, 3])
В примере выше будет работать только в том случае, если x соответствует первому значению в правом списке. В противном случае будет выдано исключение MatchError (как и оператор =).
exit(reason)Source
@spec exit(term()) :: no_return()
Останавливает выполнение вызывающего процесса с заданным основанием.
Поскольку оценка этой функции приводит к завершению процесса, она не имеет возвращаемого значения.
Компилятор встраивает эту функцию.
Примеры
Когда процесс достигает своего конца, по умолчанию он завершается с причиной :normal. Вы также можете явно вызвать exit/1, если хотите завершить процесс, но не сигнализировать об ошибке:
exit(:normal)
В случае возникновения ошибки вы также можете использовать exit/1 с другим основанием:
exit(:seems_bad)
Если причина завершения не :normal, все процессы, связанные с завершившимся процессом, аварийно завершатся (если они не обрабатывают выходы).
Выходы OTP
Выходы используются OTP для определения того, завершился ли процесс аномально или нет. Следующие выходы считаются «нормальными»:
exit(:normal)exit(:shutdown)exit({:shutdown, term})
Завершение с любой другой причиной считается аномальным и обрабатывается как сбой. Это означает, что срабатывает поведение по умолчанию супервизора, генерируются сообщения об ошибках и так далее.
Это поведение используется во многих местах. Например, ExUnit использует exit(:shutdown) при завершении тестового процесса, чтобы сигнализировать связанным процессам, деревьям управления и т. д. о вежливом завершении.
Выходы CLI
На базе сигналов завершения, упомянутых выше, если процесс, запущенный из командной строки, завершается по одной из трех причин выше, его завершение считается нормальным, и процесс операционной системы завершится со статусом 0.
Однако возможно настроить сигнал завершения операционной системы, вызвав:
exit({:shutdown, integer})
Это приведет к завершению процесса операционной системы со статусом, заданным integer, при этом всем связанным процессам Erlang будет сигнализировано о вежливом завершении.
Любая другая причина завершения приведет к завершению процесса операционной системы со статусом 1 и к аварийному завершению связанных процессов Erlang.
function_exported?(module, function, arity)Source
@spec function_exported?(module(), atom(), arity()) :: boolean()
Возвращает true если module загружен и содержит публичную function с заданным arity, в противном случае false.
Обратите внимание, что эта функция не загружает модуль в случае, если он не загружен. См. Code.ensure_loaded/1 для получения дополнительной информации.
Компилятор встраивает эту функцию.
Примеры
iex> function_exported?(Enum, :map, 2) true iex> function_exported?(Enum, :map, 10) false iex> function_exported?(List, :to_string, 1) true
get_and_update_in(path, fun)Source
Получает значение и обновляет вложенную структуру данных с помощью заданной path.
Это похоже на get_and_update_in/3, за исключением того, что путь извлекается с помощью макроса, а не передаётся в виде списка. Например:
get_and_update_in(opts[:foo][:bar], &{&1, &1 + 1})
Эквивалентно:
get_and_update_in(opts, [:foo, :bar], &{&1, &1 + 1})
Это также работает со вложенными структурами и способом указания путей struct.path.to.value.
get_and_update_in(struct.foo.bar, &{&1, &1 + 1})
Обратите внимание, что для работы этого макроса весь путь должен быть виден этому макросу. См. раздел «Пути» ниже.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users["john"].age, &{&1, &1 + 1})
{27, %{"john" => %{age: 28}, "meg" => %{age: 23}}}
Пути
Путь может начинаться с переменной, локального или удалённого вызова и должен следовать за одним или несколькими:
foo[bar]- обращается к ключуbarвfoo; в случае, еслиfooравно nil, возвращаетсяnilfoo.bar- обращается к полю карты/структуры; в случае отсутствия поля генерируется ошибка
Вот некоторые допустимые пути:
users["john"][:age] users["john"].age User.all()["john"].age all_users()["john"].age
Вот некоторые недопустимые:
# Does a remote call after the initial value users["john"].do_something(arg1, arg2) # Does not access any key or field users
get_and_update_in(data, keys, fun)Source
@spec get_and_update_in(
structure,
keys,
(term() | nil -> {current_value, new_value} | :pop)
) :: {current_value, new_structure :: structure}
when structure: Access.t(),
keys: [any(), ...],
current_value: Access.value(),
new_value: Access.value() Получает значение и обновляет вложенную структуру.
Аргумент data представляет собой вложенную структуру (то есть карту, список ключевых слов или структуру, которая реализует поведение Access).
Аргумент fun получает значение key (или nil если key отсутствует) и должен вернуть одно из следующих значений:
двухэлементная кортеж
{current_value, new_value}. В этом случаеcurrent_value- это полученное значение, которое можно обработать перед возвратом.new_value- это новое значение, которое нужно сохранить подkey.:pop, что подразумевает удаление текущего значения подkeyиз структуры и его возврат.
Эта функция использует модуль Access для обхода структур в соответствии с заданным keys, если key не является функцией, что подробно описано в последующем разделе.
Примеры
Эта функция полезна, когда нужно получить текущее значение (или значение, рассчитанное на основе текущего значения) и обновить его одновременно. Например, она может использоваться для чтения текущего возраста пользователя и увеличения его на единицу за один проход:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_and_update_in(users, ["john", :age], &{&1, &1 + 1})
{27, %{"john" => %{age: 28}, "meg" => %{age: 23}}}
Обратите внимание, что текущее значение, переданное анонимной функции, может быть nil. Если любое из промежуточных значений равно 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 не является функцией, что подробно описано в последующем разделе.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(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> users = nil
iex> get_in(users, [Access.all(), :age])
nil
Основная особенность get_in/2 заключается именно в том, что она прерывает обход, когда обнаруживает значение nil. Если вам не нужна проверка на nil, вы, скорее всего, можете написать «обычный» код Elixir:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> users["john"][:age]
27
iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> Enum.map(users, fn user -> user[:age] end)
[27, 23]
В качестве альтернативы, если вам нужно получить доступ к сложным структурам данных, вы можете использовать сопоставление с образцом:
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('bar')
"'bar'"
iex> inspect([0 | 'bar'])
"[0, 98, 97, 114]"
iex> inspect(100, base: :octal)
"0o144"
iex> inspect(100, base: :hex)
"0x64"
Обратите внимание, что протокол Inspect не обязательно возвращает корректное представление термина Elixir. В таких случаях, результат инспекции должен начинаться с #. Например, инспекция функции вернёт:
inspect(fn a, b -> a + b end) #=> #Function<...>
Протокол Inspect может быть настроен для скрытия определённых полей из структур, чтобы они не отображались в логах, результатах инспекции и подобном. Более подробную информацию можно найти в разделе «Наследование» документации протокола Inspect.
macro_exported?(module, macro, arity)Source
@spec macro_exported?(module(), atom(), arity()) :: boolean()
Возвращает true если module загружено и содержит общедоступный макрос macro с заданным arity, в противном случае false.
Обратите внимание, что эта функция не загружает модуль, если он не загружен. Смотрите Code.ensure_loaded/1 для получения дополнительной информации.
Если module является Erlang-модулем (в отличие от Elixir-модуля), эта функция всегда возвращает false.
Примеры
iex> macro_exported?(Kernel, :use, 2) true iex> macro_exported?(:erlang, :abs, 1) false
make_ref()Source
@spec make_ref() :: reference()
Возвращает почти уникальную ссылку.
Возвращаемая ссылка будет повторяться примерно после 2^82 вызовов; поэтому она достаточно уникальна для практических целей.
Встраивается компилятором.
Примеры
make_ref() #=> #Reference<0.0.0.135>
match?(pattern, expr)Source
Удобный макрос, проверяющий, соответствует ли правая часть (выражение) левой части (шаблон).
Примеры
iex> match?(1, 1)
true
iex> match?({1, _}, {1, 2})
true
iex> map = %{a: 1, b: 2}
iex> match?(%{a: _}, map)
true
iex> a = 1
iex> match?(^a, 1)
true
match?/2 очень полезен при фильтрации или поиске значения в перечислимом списке:
iex> list = [a: 1, b: 2, a: 3]
iex> Enum.filter(list, &match?({:a, _}, &1))
[a: 1, a: 3]
Также можно использовать условия-защиты для сопоставления:
iex> list = [a: 1, b: 2, a: 3]
iex> Enum.filter(list, &match?({:a, x} when x < 2, &1))
[a: 1]
Однако, переменные, присвоенные в сопоставлении, не будут доступны вне вызова функции (в отличие от обычного сопоставления с шаблоном с оператором =):
iex> match?(_x, 1) true iex> binding() []
Кроме того, помните, что оператор фиксации сопоставляет значения, а не шаблоны:
match?(%{x: 1}, %{x: 1, y: 2})
#=> true
attrs = %{x: 1}
match?(^attrs, %{x: 1, y: 2})
#=> false
Оператор фиксации проверит, равны ли значения, используя ===/2, в то время как шаблоны имеют свои правила при сопоставлении карт, списков и т. д. Такое поведение не специфично для match?/2. Следующий код также выбросит исключение:
attrs = %{x: 1}
^attrs = %{x: 1, y: 2}
#=> (MatchError) no match of right hand side value: %{x: 1, y: 2} max(first, second)Source
@spec max(first, second) :: first | second when first: term(), second: term()
Возвращает наибольшее из двух заданных значений в соответствии со структурным сравнением.
Если значения равны, возвращается первое.
Это выполняет структурное сравнение, где все термины Elixir могут быть сравнены друг с другом. Смотрите раздел «Структурное сравнение» для получения дополнительной информации.
Встраивается компилятором.
Примеры
iex> max(1, 2) 2 iex> max(:a, :b) :b
min(first, second)Source
@spec min(first, second) :: first | second when first: term(), second: term()
Возвращает наименьшее из двух заданных значений в соответствии со структурным сравнением.
Если значения равны, возвращается первое.
Это выполняет структурное сравнение, где все термины Elixir могут быть сравнены друг с другом. Смотрите раздел «Структурное сравнение» для получения дополнительной информации.
Встраивается компилятором.
Примеры
iex> min(1, 2)
1
iex> min("foo", "bar")
"bar" pop_in(path)Source
Удаляет ключ из вложенной структуры по заданному path.
Это похоже на pop_in/2, за исключением того, что путь извлекается с помощью макроса, а не передаётся в виде списка. Например:
pop_in(opts[:foo][:bar])
Эквивалентно:
pop_in(opts, [:foo, :bar])
Обратите внимание, что для работы этого макроса весь путь должен быть всегда виден этому макросу. Более подробную информацию о поддерживаемых выражениях путей, пожалуйста, см. в документации get_and_update_in/2.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> pop_in(users["john"][:age])
{27, %{"john" => %{}, "meg" => %{age: 23}}}
iex> users = %{john: %{age: 27}, meg: %{age: 23}}
iex> pop_in(users.john[:age])
{27, %{john: %{}, meg: %{age: 23}}}
В случае если любой элемент возвращает nil, его ключ будет удалён, и удаление будет считаться успешным.
pop_in(data, keys)Source
@spec pop_in(data, [Access.get_and_update_fun(term(), data) | term(), ...]) ::
{term(), data}
when data: Access.container() Удаляет ключ из заданной вложенной структуры.
Использует протокол Access для обхода структур в соответствии с заданным keys, если key не является функцией. Если ключ является функцией, он вызывается как указано в get_and_update_in/3.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> pop_in(users, ["john", :age])
{27, %{"john" => %{}, "meg" => %{age: 23}}}
В случае если любой элемент возвращает nil, его ключ будет удалён, и удаление будет считаться успешным.
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> pop_in(users, ["jane", :age])
{nil, %{"john" => %{age: 27}, "meg" => %{age: 23}}} put_elem(tuple, index, value)Source
@spec put_elem(tuple(), non_neg_integer(), term()) :: tuple()
Записывает value по заданному нулевому индексу index в tuple.
Встраивается компилятором.
Примеры
iex> tuple = {:foo, :bar, 3}
iex> put_elem(tuple, 0, :baz)
{:baz, :bar, 3} put_in(path, value)Source
Записывает значение вложенной структуры по заданному path.
Это похоже на put_in/3, за исключением того, что путь извлекается с помощью макроса, а не передаётся в виде списка. Например:
put_in(opts[:foo][:bar], :baz)
Эквивалентно:
put_in(opts, [:foo, :bar], :baz)
Это также работает с вложенными структурами и способом указания путей с помощью struct.path.to.value:
put_in(struct.foo.bar, :baz)
Обратите внимание, что для работы этого макроса весь путь должен быть всегда виден этому макросу. Более подробную информацию о поддерживаемых выражениях путей, пожалуйста, см. в документации get_and_update_in/2.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users["john"][:age], 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}}
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users["john"].age, 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}} put_in(data, keys, value)Source
@spec put_in(Access.t(), [term(), ...], term()) :: Access.t()
Помещает значение во вложенную структуру.
Использует модуль Access для обхода структур в соответствии с заданными keys, если key не является функцией. Если ключ является функцией, она будет вызвана, как указано в get_and_update_in/3.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users, ["john", :age], 28)
%{"john" => %{age: 28}, "meg" => %{age: 23}}
Если любое из промежуточных значений равно nil, будет выброшено исключение:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> put_in(users, ["jane", :age], "oops")
** (ArgumentError) could not put/update key :age on a nil value raise(message)Source
Вызывает исключение.
Если message является строкой, вызывается исключение RuntimeError с этой строкой.
Если message является атомом, просто вызывается raise/2 с атомом в качестве первого аргумента и [] в качестве второго.
Если message является структурой исключения, оно вызывается как есть.
Если message является чем-либо ещё, raise завершится с ошибкой исключения ArgumentError.
Примеры
iex> raise "oops"
** (RuntimeError) oops
try do
1 + :foo
rescue
x in [ArithmeticError] ->
IO.puts("that was expected")
raise x
end raise(exception, attributes)Source
Вызывает исключение.
Вызывает функцию exception/1 для заданного аргумента (который должен быть именем модуля, например, ArgumentError или RuntimeError), передавая attributes для получения структуры исключения.
Любой модуль, содержащий вызов макроса defexception/1, автоматически реализует обратный вызов Exception.exception/1, ожидаемый raise/2. Для получения дополнительной информации см. defexception/1.
Примеры
iex> raise(ArgumentError, "Sample") ** (ArgumentError) Sample
reraise(message, stacktrace)Source
Вызывает исключение, сохраняя предыдущий стек вызовов.
Работает как raise/1, но не создает новый стек вызовов.
Обратите внимание, что __STACKTRACE__ может использоваться внутри catch/rescue для получения текущего стека вызовов.
Примеры
try do
raise "oops"
rescue
exception ->
reraise exception, __STACKTRACE__
end reraise(exception, attributes, stacktrace)Source
Вызывает исключение, сохраняя предыдущий стек вызовов.
reraise/3 работает как reraise/2, за исключением того, что он передает аргументы функции exception/1, как объясняется в raise/2.
Примеры
try do
raise "oops"
rescue
exception ->
reraise WrapperError, [exception: exception], __STACKTRACE__
end send(dest, message)Source
@spec send(dest :: Process.dest(), message) :: message when message: any()
Отправляет сообщение заданному dest и возвращает сообщение.
dest может быть удаленным или локальным PID, локальным портом, локально зарегистрированным именем или кортежем в форме {registered_name, node} для зарегистрированного имени на другом узле.
Встраивается компилятором.
Примеры
iex> send(self(), :hello) :hello
sigil_C(term, modifiers)Source
Обрабатывает сигил ~C для списков символов.
Возвращает список символов без интерполяций и без escape-символов, за исключением экранирования закрывающего символа сигила.
Примеры
iex> ~C(foo)
'foo'
iex> ~C(f#{o}o)
'f\#{o}o' sigil_c(term, modifiers)Source
Обрабатывает сигил ~c для списков символов.
Возвращает список символов, как если бы это была строка в одинарных кавычках, раскодируя символы и заменяя интерполяции.
Примеры
iex> ~c(foo)
'foo'
iex> ~c(f#{:o}o)
'foo'
iex> ~c(f\#{:o}o)
'f\#{:o}o' sigil_D(date_string, modifiers)Source
Обрабатывает сигил ~D для дат.
По умолчанию этот сигил использует встроенный Calendar.ISO, который требует, чтобы даты записывались в формате ISO8601:
~D[yyyy-mm-dd]
например:
~D[2015-01-13]
Если вы используете альтернативные календари, можно использовать любое представление, если вы следуете представлению с одним пробелом и именем календаря:
~D[SOME-REPRESENTATION My.Alternative.Calendar]
Вариант в нижнем регистре ~d не существует, поскольку интерполяция и escape-символы не полезны для сигилов дат.
Дополнительную информацию о датах можно найти в модуле 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 не существует, поскольку интерполяция и escape-символы не полезны для сигилов дат и времени.
Дополнительную информацию о простых датах и времени можно найти в модуле 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 для регулярных выражений.
Возвращает шаблон регулярного выражения без интерполяций и без escape-символов. Обратите внимание, что он все еще поддерживает escape-последовательности для токенов Regex (например, экранирование + или ?), и также требуется экранировать закрывающий символ сигила, если он появляется в Regex.
Дополнительную информацию о регулярных выражениях можно найти в модуле Regex.
Примеры
iex> Regex.match?(~R(f#{1,3}o), "f#o")
true sigil_r(term, modifiers)Source
Обрабатывает сигил ~r для регулярных выражений.
Возвращает шаблон регулярного выражения, раскодируя символы и заменяя интерполяции.
Дополнительную информацию о регулярных выражениях можно найти в модуле Regex.
Примеры
iex> Regex.match?(~r/foo/, "foo")
true
iex> Regex.match?(~r/a#{:b}c/, "abc")
true
Хотя сигил ~r позволяет использовать круглые и квадратные скобки в качестве разделителей, предпочтительнее использовать " или / во избежание конфликтов экранирования с зарезервированными символами регулярных выражений.
sigil_S(term, modifiers)Source
Обрабатывает сигил ~S для строк.
Возвращает строку без интерполяций и без escape-символов, за исключением экранирования закрывающего символа сигила.
Примеры
iex> ~S(foo)
"foo"
iex> ~S(f#{o}o)
"f\#{o}o"
iex> ~S(\o/)
"\\o/"
Однако, если вы хотите повторно использовать сам символ сигила в строке, вам нужно экранировать его:
iex> ~S((\)) "()"
sigil_s(term, modifiers)Source
Обрабатывает сигил ~s для строк.
Возвращает строку, как если бы это была строка в двойных кавычках, раскодируя символы и заменяя интерполяции.
Примеры
iex> ~s(foo)
"foo"
iex> ~s(f#{:o}o)
"foo"
iex> ~s(f\#{:o}o)
"f\#{:o}o" sigil_T(time_string, modifiers)Source
Обрабатывает сигил ~T для времени.
По умолчанию, этот сигил использует встроенный Calendar.ISO, который требует, чтобы время было записано в формате ISO8601:
~T[hh:mm:ss] ~T[hh:mm:ss.ssssss]
например:
~T[13:00:07] ~T[13:00:07.123]
Если вы используете альтернативные календари, можно использовать любое представление, если за ним следует пробел и имя календаря:
~T[SOME-REPRESENTATION My.Alternative.Calendar]
Вариант ~t в нижнем регистре не существует, так как интерполяция и символы экранирования не полезны для сигилов времени.
Дополнительную информацию о времени можно найти в модуле Time.
Примеры
iex> ~T[13:00:07] ~T[13:00:07] iex> ~T[13:00:07.001] ~T[13:00:07.001]
sigil_U(datetime_string, modifiers)Source
Обрабатывает сигил ~U для создания UTC DateTime.
По умолчанию, этот сигил использует встроенный Calendar.ISO, который требует, чтобы UTC-даты и время были записаны в формате ISO8601:
~U[yyyy-mm-dd hh:mm:ssZ] ~U[yyyy-mm-dd hh:mm:ss.ssssssZ] ~U[yyyy-mm-ddThh:mm:ss.ssssss+00:00]
например:
~U[2015-01-13 13:00:07Z] ~U[2015-01-13T13:00:07.123+00:00]
Если вы используете альтернативные календари, можно использовать любое представление, если за ним следует пробел и имя календаря:
~U[SOME-REPRESENTATION My.Alternative.Calendar]
Указанный datetime_string должен содержать смещение "Z" или "00:00", что указывает на UTC; в противном случае возникает ошибка.
Вариант ~u в нижнем регистре не существует, так как интерполяция и символы экранирования не полезны для сигилов дат и времени.
Дополнительную информацию о датах и времени можно найти в модуле DateTime.
Примеры
iex> ~U[2015-01-13 13:00:07Z] ~U[2015-01-13 13:00:07Z] iex> ~U[2015-01-13T13:00:07.001+00:00] ~U[2015-01-13 13:00:07.001Z]
sigil_W(term, modifiers)Source
Обрабатывает сигил ~W для списка слов.
Возвращает список "слов", разделенных пробелами, без интерполяции и символов экранирования, кроме экранирования закрывающего символа сигила.
Модификаторы
-
s: слова в списке являются строками (по умолчанию) -
a: слова в списке являются атомами -
c: слова в списке являются списками символов
Примеры
iex> ~W(foo #{bar} baz)
["foo", "\#{bar}", "baz"] sigil_w(term, modifiers)Source
Обрабатывает сигил ~w для списка слов.
Возвращает список "слов", разделенных пробелами. Разъяснение символов и интерполяция происходят для каждого слова.
Модификаторы
-
s: слова в списке являются строками (по умолчанию) -
a: слова в списке являются атомами -
c: слова в списке являются списками символов
Примеры
iex> ~w(foo #{:bar} baz)
["foo", "bar", "baz"]
iex> ~w(foo #{" bar baz "})
["foo", "bar", "baz"]
iex> ~w(--source test/enum_test.exs)
["--source", "test/enum_test.exs"]
iex> ~w(foo bar baz)a
[:foo, :bar, :baz]
iex> ~w(foo bar baz)c
['foo', 'bar', 'baz'] spawn(fun)Source
@spec spawn((() -> any())) :: pid()
Запускает заданную функцию и возвращает её PID.
Обычно разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
Проверьте модуль Process для получения дополнительных функций, связанных с процессами.
Анонимная функция получает 0 аргументов и может возвращать любое значение.
Встроено компилятором.
Примеры
current = self()
child = spawn(fn -> send(current, {self(), 1 + 2}) end)
receive do
{^child, 3} -> IO.puts("Received 3 back")
end spawn(module, fun, args)Source
@spec spawn(module(), atom(), list()) :: pid()
Запускает заданную функцию fun из указанного module, передавая ей указанные args, и возвращает её PID.
Обычно разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
Проверьте модуль Process для получения дополнительных функций, связанных с процессами.
Встроено компилятором.
Примеры
spawn(SomeModule, :function, [1, 2, 3])
spawn_link(fun)Source
@spec spawn_link((() -> any())) :: pid()
Запускает заданную функцию, связывает её с текущим процессом и возвращает её PID.
Обычно разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
Проверьте модуль Process для получения дополнительных функций, связанных с процессами. Для получения более подробной информации о связывании, см. Process.link/1.
Анонимная функция получает 0 аргументов и может возвращать любое значение.
Встроено компилятором.
Примеры
current = self()
child = spawn_link(fn -> send(current, {self(), 1 + 2}) end)
receive do
{^child, 3} -> IO.puts("Received 3 back")
end spawn_link(module, fun, args)Source
@spec spawn_link(module(), atom(), list()) :: pid()
Запускает заданную функцию fun из указанного module, передавая ей указанные args, связывает её с текущим процессом и возвращает её PID.
Обычно разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
Проверьте модуль Process для получения дополнительных функций, связанных с процессами. Для получения более подробной информации о связывании, см. Process.link/1.
Встроено компилятором.
Примеры
spawn_link(SomeModule, :function, [1, 2, 3])
spawn_monitor(fun)Source
@spec spawn_monitor((() -> any())) :: {pid(), reference()} Запускает заданную функцию, отслеживает её и возвращает её PID и ссылку отслеживания.
Обычно разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
Проверьте модуль Process для получения дополнительных функций, связанных с процессами.
Анонимная функция получает 0 аргументов и может возвращать любое значение.
Встроено компилятором.
Примеры
current = self()
spawn_monitor(fn -> send(current, {self(), 1 + 2}) end) spawn_monitor(module, fun, args)Source
@spec spawn_monitor(module(), atom(), list()) :: {pid(), reference()} Запускает указанный модуль и функцию, передавая заданные аргументы, отслеживает его и возвращает его PID и ссылку отслеживания.
Обычно разработчики не используют функции spawn, вместо этого они используют абстракции, такие как Task, GenServer и Agent, построенные поверх spawn, которые запускают процессы с большей удобством с точки зрения интроспекции и отладки.
Проверьте модуль Process для получения дополнительных функций, связанных с процессами.
Встроено компилятором.
Примеры
spawn_monitor(SomeModule, :function, [1, 2, 3])
struct!(struct, fields \\ [])Source
@spec struct!(module() | struct(), Enum.t()) :: struct()
Аналогично struct/2, но проверяет корректность ключей.
Функция struct!/2 эмулирует поведение структур во время компиляции. Это означает, что:
при создании структуры, как в
struct!(SomeStruct, key: :value), она эквивалентна%SomeStruct{key: :value}и, следовательно, эта функция проверит, принадлежит ли каждая пара ключ-значение структуре. Если структура требует определённые ключи через@enforce_keys, они также будут проверены;при обновлении структуры, как в
struct!(%SomeStruct{}, key: :value), она эквивалентна%SomeStruct{struct | key: :value}и, следовательно, эта функция проверит, принадлежит ли каждая пара ключ-значение структуре. Однако, при обновлении структуры ключи не проверяются, поскольку проверка ключей выполняется только при создании;
struct(struct, fields \\ [])Source
@spec struct(module() | struct(), Enum.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"} tap(value, fun)Source
Передаёт value в заданную fun и возвращает исходное значение value.
Полезно для выполнения синхронных побочных эффектов в конвейере.
Примеры
iex> tap(1, fn x -> x + 1 end) 1
Чаще всего это используется в конвейерах. Например, предположим, что вы хотите проверить часть структуры данных. Вы можете написать:
%{a: 1}
|> Map.update!(:a, & &1 + 2)
|> tap(&IO.inspect(&1.a))
|> Map.update!(:a, & &1 * 2) then(value, fun)Source
Передаёт value в заданную fun.
Другими словами, это вызывает fun с value в качестве аргумента. Это наиболее часто используется в конвейерах, позволяя вам передать значение в функцию вне её первого аргумента.
Примеры
iex> 1 |> then(fn x -> x * 2 end) 2 iex> 1 |> then(fn x -> Enum.drop(["a", "b", "c"], x) end) ["b", "c"]
throw(term)Source
@spec throw(term()) :: no_return()
Нелокальный возврат из функции.
См. Kernel.SpecialForms.try/1 для получения дополнительной информации.
Встраивается компилятором.
to_charlist(term)Source
Преобразует данный терм в charlist в соответствии с протоколом List.Chars.
Примеры
iex> to_charlist(:foo) 'foo'
to_string(term)Source
Преобразует аргумент в строку в соответствии с протоколом String.Chars.
Это функция, вызываемая при интерполяции строк.
Примеры
iex> to_string(:foo) "foo"
unless(condition, clauses)Source
Обеспечивает макрос unless.
Этот макрос вычисляет и возвращает блок do переданный во втором аргументе, если condition вычисляет значение ложное (false или nil). В противном случае возвращает значение блока else, если он есть, или nil, если нет.
См. также if/2.
Примеры
iex> unless(Enum.empty?([]), do: "Hello") nil iex> unless(Enum.empty?([1, 2, 3]), do: "Hello") "Hello" iex> unless Enum.sum([2, 2]) == 5 do ...> "Math still works" ...> else ...> "Math is broken" ...> end "Math still works"
update_in(path, fun)Source
Обновляет вложенную структуру с помощью заданной path.
Это аналогично update_in/3, за исключением того, что путь извлекается с помощью макроса, а не передаётся в виде списка. Например:
update_in(opts[:foo][:bar], &(&1 + 1))
Эквивалентно:
update_in(opts, [:foo, :bar], &(&1 + 1))
Это также работает со вложенными структурами и способом указания путей с struct.path.to.value:
update_in(struct.foo.bar, &(&1 + 1))
Обратите внимание, что для работы этого макроса весь путь должен быть виден этому макросу. Более подробную информацию о поддерживаемых выражениях путей можно найти в документации get_and_update_in/2.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users["john"][:age], &(&1 + 1))
%{"john" => %{age: 28}, "meg" => %{age: 23}}
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users["john"].age, &(&1 + 1))
%{"john" => %{age: 28}, "meg" => %{age: 23}} update_in(data, keys, fun)Source
@spec update_in(Access.t(), [term(), ...], (term() -> term())) :: Access.t()
Обновляет ключ во вложенной структуре.
Использует модуль Access для перемещения по структурам в соответствии с заданным keys, если key не является функцией. Если ключ — функция, она вызывается в соответствии с описанием в get_and_update_in/3.
data — это вложенная структура (то есть, карта, список ключевых слов или структура, реализующая поведение Access). Аргумент fun получает значение key (или nil если key отсутствует), а результат заменяет значение в структуре.
Примеры
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users, ["john", :age], &(&1 + 1))
%{"john" => %{age: 28}, "meg" => %{age: 23}}
Обратите внимание, что текущее значение, переданное анонимной функции, может быть nil. Если любое из промежуточных значений равно nil, будет возбуждено исключение:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> update_in(users, ["jane", :age], & &1 + 1)
** (ArgumentError) could not put/update key :age on a nil value use(module, opts \\ [])Source
Использует указанный модуль в текущем контексте.
При вызове:
use MyModule, some: :options
макрос __using__/1 из модуля MyModule вызывается со вторым аргументом, переданным в use, в качестве аргумента. Поскольку __using__/1 является макросом, применяются все обычные правила макросов, а его возвращаемое значение должно быть кодом в кавычках, который затем вставляется туда, где вызывается use/2.
Примеры
Например, для написания тестовых случаев с использованием фреймворка ExUnit, предоставляемого Elixir, разработчик должен использовать модуль ExUnit.Case:
defmodule AssertionTest do
use ExUnit.Case, async: true
test "always pass" do
assert true
end
end
В этом примере Elixir вызовет макрос __using__/1 в модуле ExUnit.Case с ключевым списком [async: true] в качестве аргумента.
Другими словами, use/2 преобразуется в:
defmodule AssertionTest do
require ExUnit.Case
ExUnit.Case.__using__(async: true)
test "always pass" do
assert true
end
end
где ExUnit.Case определяет макрос __using__/1:
defmodule ExUnit.Case do
defmacro __using__(opts) do
# do something with opts
quote do
# return some code to inject in the caller
end
end
end
Рекомендации по наилучшей практике
__using__/1 обычно используется, когда необходимо установить некоторое состояние (через атрибуты модуля) или обратные вызовы (например, @before_compile, см. документацию по Module для получения дополнительной информации) в вызывающий модуль.
__using__/1 также может использоваться для алиасирования, требования или импорта функциональности из различных модулей:
defmodule MyModule do
defmacro __using__(_opts) do
quote do
import MyModule.Foo
import MyModule.Bar
import MyModule.Baz
alias MyModule.Repo
end
end
end
Однако не предоставляйте __using__/1 если все, что оно делает, это импортирует, создает алиас или требует самого модуля. Например, избегайте этого:
defmodule MyModule do
defmacro __using__(_opts) do
quote do
import MyModule
end
end
end
В таких случаях разработчики должны вместо этого напрямую импортировать или создать алиас модуля, чтобы они могли настроить их по своему желанию без косвенности через use/2.
Наконец, разработчики также должны избегать определения функций внутри обратного вызова __using__/1, если эти функции не являются реализацией по умолчанию ранее определенного @callback или являются функциями, предназначенными для переопределения (см. defoverridable/1). Даже в этих случаях определение функций следует рассматривать как "последнее средство".
Если вы хотите предоставить существующую функциональность модулю пользователя, определите ее в модуле, который будет импортироваться соответственно; например, ExUnit.Case не определяет макрос test/3 в модуле, вызывающем use ExUnit.Case, но он определяет ExUnit.Case.test/3 и просто импортирует его в вызывающий модуль при использовании.
var!(var, context \\ nil)Source
Помечает, что заданная переменная не должна подвергаться санизации.
Этот макрос ожидает переменную и обычно вызывается внутри Kernel.SpecialForms.quote/2 для обозначения того, что переменная не должна подвергаться санизации. См. Kernel.SpecialForms.quote/2 для получения дополнительной информации.
Примеры
iex> Kernel.var!(example) = 1 1 iex> Kernel.var!(example) 1
left |> rightSource
Оператор конвейера.
Этот оператор вводит выражение слева в качестве первого аргумента вызова функции справа.
Примеры
iex> [1, [2], 3] |> List.flatten() [1, 2, 3]
Приведенный выше пример эквивалентен вызову List.flatten([1, [2], 3]).
Оператор |> в основном полезен, когда требуется выполнить серию операций, напоминающих конвейер:
iex> [1, [2], 3] |> List.flatten() |> Enum.map(fn x -> x * 2 end) [2, 4, 6]
В приведенном выше примере список [1, [2], 3] передается в качестве первого аргумента функции List.flatten/1, затем сглаженный список передается в качестве первого аргумента функции Enum.map/2, которая удваивает каждый элемент списка.
Другими словами, приведенное выше выражение просто преобразуется в:
Enum.map(List.flatten([1, [2], 3]), fn x -> x * 2 end)
Возможные ошибки
Существует две распространенные ошибки при использовании оператора конвейера.
Первая связана с приоритетом оператора. Например, следующее выражение:
String.graphemes "Hello" |> Enum.reverse
Преобразуется в:
String.graphemes("Hello" |> Enum.reverse())
что приводит к ошибке, поскольку протокол Enumerable не определен для двоичных данных. Добавление явных скобок устраняет неоднозначность:
String.graphemes("Hello") |> Enum.reverse()
Или, еще лучше:
"Hello" |> String.graphemes() |> Enum.reverse()
Вторая ограничение заключается в том, что Elixir всегда выполняет конвейер с вызовом функции. Таким образом, для конвейера в анонимную функцию необходимо вызвать ее:
some_fun = &Regex.replace(~r/l/, &1, "L") "Hello" |> some_fun.()
В качестве альтернативы вы можете использовать then/2 для того же эффекта:
some_fun = &Regex.replace(~r/l/, &1, "L") "Hello" |> then(some_fun)
then/2 чаще всего используется, когда вы хотите выполнить конвейер в функцию, но значение ожидается вне первого аргумента, как выше. Заменив some_fun его значением, мы получим:
"Hello" |> then(&Regex.replace(~r/l/,&1, "L"))
left || rightSource
Булевый оператор "или".
Предоставляет оператор короткого замыкания, который вычисляет и возвращает второе выражение только в том случае, если первое выражение не вычисляет истинное значение (то есть, оно либо nil или false). В противном случае возвращает первое выражение.
Не допускается в операторах-условиях.
Примеры
iex> Enum.empty?([1]) || Enum.empty?([1]) false iex> List.first([]) || true true iex> Enum.empty?([1]) || 1 1 iex> Enum.empty?([]) || throw(:bad) true
Обратите внимание, что в отличие от or/2, этот оператор принимает любое выражение в качестве первого аргумента, а не только булевы значения.
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.13.4/Kernel.html