Spec-Zone.ru › Elixir 1.5

Ядро

Предоставляет стандартные макросы и функции, которые Elixir импортирует в вашу среду.

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

import Kernel, except: [if: 2]

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

Некоторые функции, описанные в этом модуле, встроены компилятором Elixir в свои аналоги в Erlang в :erlang модуле. Эти функции называются BIF (встроенные внутренние функции) в мире Erlang, и они обладают интересными свойствами, так как некоторые из них разрешены в условиях и используются для оптимизации компилятора.

Большинство встроенных функций можно увидеть в действии при захвате функции:

iex> &Kernel.is_atom/1
&:erlang.is_atom/1

Эти функции будут явно отмечены в их документации как «встроенные компилятором».

Обзор

Функции

!value

Логическое отрицание

left != right

Возвращает true если два элемента не равны

left !== right

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

left && right

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

left * right

Арифметическое умножение

+value

Арифметическое унарное сложение

left + right

Арифметическое сложение

left ++ right

Конкатенирует правильный список и термин, возвращая список

-value

Арифметическое унарное вычитание

left - right

Арифметическое вычитание

left -- right

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

first..last

Возвращает диапазон с указанными first и last целыми числами

left / right

Арифметическое деление

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

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

Конкатенирует два бинарных значения

left == right

Возвращает true если два элемента равны

left === right

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

left =~ right

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

left > right

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

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

@expr

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

abs(number)

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

alias!(alias)

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

left and right

Логическое И

apply(fun, args)

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

apply(module, fun, args)

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

binary_part(binary, start, length)

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

binding(context \\ nil)

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

bit_size(bitstring)

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

byte_size(bitstring)

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

def(call, expr \\ nil)

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

defdelegate(funs, opts)

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

defexception(fields)

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

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)

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

div(dividend, divisor)

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

elem(tuple, index)

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

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)

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

hd(list)

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

if(condition, clauses)

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

left in right

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

inspect(term, opts \\ [])

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

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_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_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_tuple(term)

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

length(list)

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

macro_exported?(module, macro, arity)

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

make_ref()

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

map_size(map)

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

match?(pattern, expr)

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

max(first, second)

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

min(first, second)

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

node()

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

node(arg)

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

not value

Логическое отрицание

left or right

Логическое ИЛИ

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)

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

rem(dividend, divisor)

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

reraise(message, stacktrace)

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

reraise(exception, attributes, stacktrace)

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

round(number)

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

self()

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

send(dest, message)

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

sigil_C(term, modifiers)

Обрабатывает сигил ~C

sigil_D(date, modifiers)

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

sigil_N(date, modifiers)

Обрабатывает сигил ~N для даты и времени без учета часового пояса

sigil_R(term, modifiers)

Обрабатывает сигил ~R

sigil_S(term, modifiers)

Обрабатывает сигил ~S

sigil_T(date, modifiers)

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

sigil_W(term, modifiers)

Обрабатывает сигил ~W

sigil_c(term, modifiers)

Обрабатывает сигил ~c

sigil_r(term, modifiers)

Обрабатывает сигил ~r

sigil_s(term, modifiers)

Обрабатывает сигил ~s

sigil_w(term, modifiers)

Обрабатывает сигил ~w

spawn(fun)

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

spawn(module, fun, args)

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

spawn_link(fun)

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

spawn_link(module, fun, args)

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

spawn_monitor(fun)

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

spawn_monitor(module, fun, args)

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

struct(struct, fields \\ [])

Создаёт и обновляет структуры

struct!(struct, fields \\ [])

Аналогично struct/2, но проверяет корректность ключей

throw(term)

Нелокальный возврат из функции

tl(list)

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

to_charlist(term)

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

to_string(term)

Преобразует аргумент в строку в соответствии с протоколом String.Chars

trunc(number)

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

tuple_size(tuple)

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

unless(condition, clauses)

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

update_in(path, fun)
END_OF_DOCUMENT_MARKER

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

update_in(data, keys, fun)

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

use(module, opts \\ [])

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

var!(var, context \\ nil)

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

left |> right

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

left || right

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

Функции

!value (макрос)

Логическое отрицание.

Принимает любой аргумент (а не только булевые значения) и возвращает true, если аргумент false или nil; в противном случае возвращает %%%CODE_BLOCK_136%%.

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

Примеры

iex> !Enum.empty?([])
false

iex> !List.first([])
true

left != right

term() != term() :: boolean()

Возвращает true, если два элемента не равны.

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

Все термины в Elixir можно сравнивать друг с другом.

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

Примеры

iex> 1 != 2
true

iex> 1 != 1.0
false

left !== right

term() !== term() :: boolean()

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

Все термины в Elixir можно сравнивать друг с другом.

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

Примеры

iex> 1 !== 2
true

iex> 1 !== 1.0
true

left && right (макрос)

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

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

Примеры

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

left * right

integer() * integer() :: integer()
float() * float() :: float()
integer() * float() :: float()
float() * integer() :: float()

Арифметическое умножение.

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

Примеры

iex> 1 * 2
2

+value

+value :: value when value: number()

Арифметическое унарное плюс.

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

Примеры

iex> +1
1

left + right

integer() + integer() :: integer()
float() + float() :: float()
integer() + float() :: float()
float() + integer() :: float()

Арифметическое сложение.

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

Примеры

iex> 1 + 2
3

left ++ right

list() ++ term() :: maybe_improper_list()

Конкатенирует правильный список и термин, возвращая список.

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

-value

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

Арифметическое унарное минус.

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

Примеры

iex> -2
-2

left - right

integer() - integer() :: integer()
float() - float() :: float()
integer() - float() :: float()
float() - integer() :: float()

Арифметическое вычитание.

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

Примеры

iex> 1 - 2
-1

left -- right

list() -- list() :: list()

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

Сложность a -- b пропорциональна length(a) * length(b), что означает, что она будет очень медленной, если оба a и b являются длинными списками. В таких случаях рассмотрите преобразование каждого списка в MapSet и использование MapSet.difference/2.

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

Примеры

iex> [1, 2, 3] -- [1, 2]
[3]

iex> [1, 2, 3, 2, 1] -- [1, 2, 2]
[3, 1]

first..last (макрос)

Возвращает диапазон с указанными first и last целыми числами.

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

Примеры

iex> 0 in 1..3
false

iex> 1 in 1..3
true

iex> 2 in 1..3
true

iex> 3 in 1..3
true

left / right

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 < right

term() < term() :: boolean()

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

Все термины в Elixir можно сравнивать друг с другом.

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

Примеры

iex> 1 < 2
true

left <= right

term() <= term() :: boolean()

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

Все термины в Elixir можно сравнивать друг с другом.

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

Примеры

iex> 1 <= 2
true

left <> right (макрос)

Конкатенирует две бинарные строки.

Примеры

iex> "foo" <> "bar"
"foobar"

Оператор <> также может быть использован в сопоставлении с образцом (и условиях охраны), если первая часть является литеральной бинарной строкой:

iex> "foo" <> x = "foobar"
iex> x
"bar"

x <> "bar" = "foobar" привело бы к исключению CompileError.

left == right

term() == term() :: boolean()

Возвращает true, если два элемента равны.

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

Все термины в Elixir можно сравнивать друг с другом.

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

Примеры

iex> 1 == 2
false

iex> 1 == 1.0
true

left === right

term() === term() :: boolean()

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

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

Все термины в Elixir можно сравнивать друг с другом.

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

Примеры

iex> 1 === 2
false

iex> 1 === 1.0
false

left =~ right

String.t() =~ String.t() | Regex.t() :: boolean()

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

Возвращает true, если left соответствует right (если это регулярное выражение) или содержит right (если это строка).

Примеры

iex> "abcd" =~ ~r/c(d)/
true

iex> "abcd" =~ ~r/e/
false

iex> "abcd" =~ "bc"
true

iex> "abcd" =~ "ad"
false

iex> "abcd" =~ ""
true

left > right

term() > term() :: boolean()

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

Все термины в Elixir можно сравнивать друг с другом.

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

Примеры

iex> 1 > 2
false

left >= right

term() >= term() :: boolean()

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

Все термины в Elixir можно сравнивать друг с другом.

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

Примеры

iex> 1 >= 2
false

@expr (макрос)

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

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

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

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

abs(number)

abs(number()) :: number()

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

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

Примеры

iex> abs(-3.33)
3.33

iex> abs(-3)
3

alias!(alias) (макрос)

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

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

left and right (макрос)

Логическое И.

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

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

Разрешено в тестах условий.

Примеры

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

apply(fun, args)

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

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

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

Примеры

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

apply(module, fun, args)

apply(module(), atom(), [any()]) :: any()

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

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

Примеры

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

binary_part(binary, start, length)

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"

binding(context \\ nil) (макрос)

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

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

Если заданный 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]

bit_size(bitstring)

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)

byte_size(bitstring()) :: non_neg_integer()

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

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

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

Примеры

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

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

def(call, expr \\ nil) (макрос)

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

Примеры

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

Компилятор преобразует это в несколько функций с различными арностью, здесь Foo.multiply_by/1 и Foo.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

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

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

Имена функций и переменных имеют следующий синтаксис: строчная буква 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

Тела функций поддерживают rescue, catch и after как SpecialForms.try/1.

Следующие две функции эквивалентны:

def format(value) do
  try do
    format!(value)
  catch
    :exit, reason -> {:error, reason}
  end
end

def format(value) do
  format!(value)
catch
  :exit, reason -> {:error, reason}
end

defdelegate(funs, opts) (макрос)

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

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

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

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

Параметры

  • :to - модуль, которому делегируется вызов.

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

Примеры

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

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

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

defexception(fields) (макрос)

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

Исключения — структуры, поддерживаемые модулем, реализующим поведение 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]

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

raise MyAppError, value

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

defimpl(name, opts, do_block \\ []) (макрос)

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

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

Внутри реализации имя протокола можно получить с помощью @protocol, а текущую цель — с помощью @for.

defmacro(call, expr \\ nil) (макрос)

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

См. 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) (макрос)

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

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

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

defmodule(alias, do_block) (макрос)

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

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

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

Примеры

iex> defmodule Foo do
...>   def bar, do: :baz
...> end
iex> Foo.bar
:baz

Вложенность

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

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 предоставляет специальный синтаксис, обычно используемый для имён модулей. Имя модуля — это заглавная буква ASCII, за которой следует любое количество строчных или заглавных букв ASCII, цифр или подчёркиваний. Этот идентификатор эквивалентен атому, префиксуемому Elixir.. Таким образом, в примере defmodule Foo Foo эквивалентно :"Elixir.Foo"

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

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

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

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

defoverridable(keywords_or_behaviour) (макрос)

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

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

Пример

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
    "Overriden"
  end
end

defp(call, expr \\ nil) (макрос)

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

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

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

Протокол определяет API, который должны реализовывать его реализации.

Примеры

В Elixir есть два глагола для проверки количества элементов в структуре данных: length и size. length означает, что информация должна быть вычислена. Например, length(list) нужно пройти по всему списку, чтобы вычислить его длину. С другой стороны, tuple_size(tuple) и byte_size(binary) не зависят от размера кортежа и двоичного файла, поскольку информация о размере предварительно вычислена в структуре данных.

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

defprotocol Size do
  @doc "Calculates the size (and not the length!) of a data structure"
  def size(data)
end

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

defimpl Size, for: BitString do
  def size(binary), do: byte_size(binary)
end

defimpl Size, for: Map do
  def size(map), do: map_size(map)
end

defimpl Size, for: Tuple do
  def size(tuple), do: tuple_size(tuple)
end

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

Можно реализовать протоколы для всех типов Elixir:

  • Структуры (см. ниже)
  • Tuple
  • Atom
  • List
  • BitString
  • Integer
  • Float
  • Function
  • PID
  • Map
  • Port
  • Reference
  • Any (см. ниже)

Протоколы и структуры

Настоящая польза протоколов проявляется при использовании их вместе со структурами. Например, Elixir поставляется со многими типами данных, реализованными как структуры, например, MapSet. Мы можем реализовать протокол Size для этих типов также:

defimpl Size, for: MapSet do
  def size(map_set), do: MapSet.size(map_set)
end

При реализации протокола для структуры, опцию :for можно опустить, если вызов defimpl находится внутри модуля, определяющего структуру:

defmodule User do
  defstruct [:email, :name]

  defimpl Size do
    def size(%User{}), do: 2 # two fields
  end
end

Если реализация протокола для данного типа не найдена, вызов протокола вызовет исключение, если не настроено обращение к Any. Удобства для построения реализаций на основе существующих также доступны, см. defstruct/1 для получения дополнительной информации о выводе протоколов.

Обращение к любому

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

defprotocol Size do
  @fallback_to_any true
  def size(data)
end

Протокол Size теперь можно реализовать для Any:

defimpl Size, for: Any do
  def size(_), do: 0
end

Хотя приведенная выше реализация, вероятно, не является разумной. Например, нет смысла говорить, что PID или целое число имеют размер 0. Это одна из причин, почему @fallback_to_any является поведенческой особенностью, которая используется по выбору. Для большинства протоколов поднятие ошибки при отсутствии реализации — это правильное поведение.

Типы

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

@spec print_size(Size.t) :: :ok
def print_size(data) do
  IO.puts(case Size.size(data) do
    0 -> "data has no items"
    1 -> "data has one item"
    n -> "data has #{n} items"
  end)
end

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

Рефлексия

Любой модуль протокола содержит три дополнительные функции:

  • __protocol__/1 — возвращает имя протокола, когда :name, список ключевых слов с функциями протокола и их арностью, когда :functions, и список реализаций, когда :impls

  • impl_for/1 — получает структуру и возвращает модуль, реализующий протокол для структуры, nil в противном случае

  • impl_for!/1 — то же, что выше, но генерирует ошибку, если реализация не найдена

    Enumerable.__protocol__(:functions)
    #=> [count: 1, member?: 2, reduce: 3]
    
    Enumerable.impl_for([])
    #=> Enumerable.List
    
    Enumerable.impl_for(42)
    #=> nil

Консолидация

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

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

Консолидация протоколов применяется по умолчанию ко всем проектам Mix. Для ручной реализации консолидации см. функции в модуле Protocol или задачу mix compile.protocols.

defstruct(fields) (макрос)

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

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

Чтобы определить структуру, разработчик должен определить функции __struct__/0 и __struct__/1. defstruct/1 — это макрос-удобство, который определяет такие функции с некоторыми удобствами.

Для получения дополнительной информации о структурах см. Kernel.SpecialForms.%/2.

Примеры

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

Поля структуры оцениваются во время компиляции, что позволяет им быть динамическими. В приведенном ниже примере 10 + 11 оценивается во время компиляции, и поле возраста хранится со значением 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) #=> works

Для каждого протокола в списке @derive Elixir проверит наличие реализации этого протокола для любого (независимо от того, использует ли обращение к любому true) и проверит, определяет ли любая реализация обратный вызов __deriving__/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 :: %User{name: String.t, age: non_neg_integer}
end

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

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

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

destructure(left, right) (макрос)

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

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

Примеры

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 (как и оператор =).

div(делимое, делитель)

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(кортеж, индекс)

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

Возвращает элемент по нулевому индексу в tuple.

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

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

Примеры

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

elem({}, 0)
#=> ** (ArgumentError) argument error

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

exit(причина)

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 , одновременно сигнализируя всем связанным OTP-процессам о корректном завершении.

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

function_exported?(модуль, функция, арность)

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

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

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

Примеры

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

get_and_update_in(путь, функция) (макрос)

Получает значение и обновляет вложенную структуру данных с помощью указанной 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})

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

Примеры

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

Пути

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

  • foo[bar] — обращается к ключу bar в foo; в случае, если foo равно null, возвращается nil

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

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

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

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

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

# Does not access any key or field
users

get_and_update_in(данные, ключи, функция)

get_and_update_in(structure :: Access.t(), keys, (term() -> {get_value, update_value} | :pop)) :: {get_value, structure :: Access.t()} when keys: [any(), ...], update_value: term(), get_value: var

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

data — это вложенная структура (например, карта, список ключевых слов или структура, реализующая поведение Access).

Аргумент fun получает значение key (или nil , если key отсутствует) и должен возвращать кортеж из двух элементов: значение «получения» (полученное значение, которое можно обработать перед возвратом) и новое значение, которое нужно сохранить под key. Функция fun также может возвращать :pop, что подразумевает удаление текущего значения из структуры и его возврат.

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

Если ключ является функцией, функция вызывается с тремя аргументами: операция (:get_and_update), данные для доступа и функция, которая вызывается далее.

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

Примеры

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

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}}}

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

iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> all = fn :get_and_update, data, next ->
...>   Enum.map(data, next) |> :lists.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(данные, ключи)

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

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

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

Если ключ является функцией, функция вызывается с тремя аргументами: операция (:get), данные для доступа и функция, которая вызывается далее.

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

Примеры

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

В случае если какой-либо из элементов в середине возвращает nil, nil будет возвращено в соответствии с модулем доступа:

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

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

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]

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

hd(список)

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

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

Работает с некорректными списками.

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

Примеры

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

hd([])
#=> ** (ArgumentError) argument error

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

if(condition, clauses) (macro)

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

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

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

if(foo, do: bar)

В примере выше, bar будет возвращено, если foo вычисляется как true (то есть это ни 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.

left in right (macro)

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

Примеры

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

При использовании диапазонов:

when x in 1..3

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

when is_integer(x) and x >= 1 and x <= 3

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

Рассмотрение AST

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

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

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

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

inspect(term, opts \\ [])

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<...>

is_atom(term)

is_atom(term()) :: boolean()

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

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

is_binary(term)

is_binary(term()) :: boolean()

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

Бинарное значение всегда содержит полное количество байтов.

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

Примеры

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

is_bitstring(term)

is_bitstring(term()) :: boolean()

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

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

Примеры

iex> is_bitstring "foo"
true
iex> is_bitstring <<1::3>>
true

is_boolean(term)

is_boolean(term()) :: boolean()

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

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

is_float(term)

is_float(term()) :: boolean()

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

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

is_function(term)

is_function(term()) :: boolean()

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

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

is_function(term, arity)

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)

is_integer(term()) :: boolean()

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

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

is_list(term)

is_list(term()) :: boolean()

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

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

is_map(term)

is_map(term()) :: boolean()

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

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

is_nil(term) (macro)

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

Допускается в условиях-ограничениях.

Примеры

iex> is_nil(1)
false

iex> is_nil(nil)
true

is_number(term)

is_number(term()) :: boolean()

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

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

is_pid(term)

is_pid(term()) :: boolean()

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

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

is_port(term)

is_port(term()) :: boolean()

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

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

is_reference(term)

is_reference(term()) :: boolean()

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

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

is_tuple(term)

is_tuple(term()) :: boolean()

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

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

length(list)

length(list()) :: non_neg_integer()

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

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

Примеры

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

macro_exported?(module, macro, arity)

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

make_ref() :: reference()

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

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

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

Примеры

make_ref() #=> #Reference<0.0.0.135>

map_size(map)

map_size(map()) :: non_neg_integer()

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

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

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

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

Примеры

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

match?(pattern, expr) (macro)

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

Примеры

iex> match?(1, 1)
true

iex> match?(1, 2)
false

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

max(first, second)

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

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

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

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

Примеры

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

min(first, second)

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

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

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

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

Примеры

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

node()

node() :: node()

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

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

node(arg)

node(pid() | reference() | port()) :: node()

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

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

not value

not true :: false
not false :: true

Логическое отрицание.

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

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

Примеры

iex> not false
true

left or right (макрос)

Логическое ИЛИ.

Если первый аргумент true, возвращается true; в противном случае — второй аргумент.

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

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

Примеры

iex> true or false
true
iex> false or 42
42

pop_in(path) (макрос)

Удаляет ключ из вложенной структуры по заданному 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)

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

put_elem(tuple, index, value)

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) (макрос)

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

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

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

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

put_in(opts, [: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)

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, при попытке следующего доступа возникнет ошибка.

raise(message) (макрос)

Генерирует исключение.

Если аргумент msg является двоичным, генерируется исключение RuntimeError с заданным аргументом в качестве сообщения.

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

Если msg — структура исключения, она генерируется как есть.

Если msg — что-либо другое, возникнет исключение 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) (макрос)

Генерирует исключение.

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

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

Примеры

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

rem(dividend, divisor)

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

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

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

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

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

Примеры

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

reraise(message, stacktrace) (макрос)

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

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

Обратите внимание, что System.stacktrace/0 возвращает стек вызовов последнего исключения. При этом, часто стек вызовов присваивается в качестве первого выражения в блоке rescue , так как любое другое потенциально сгенерированное (и перехваченное) исключение между блоком обработки исключения и вызовом raise может изменить значение System.stacktrace/0.

Примеры

try do
  raise "oops"
rescue
  exception ->
    stacktrace = System.stacktrace
    if Exception.message(exception) == "oops" do
      reraise exception, stacktrace
    end
end

reraise(exception, attributes, stacktrace) (макрос)

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

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

Примеры

try do
  raise "oops"
rescue
  exception ->
    stacktrace = System.stacktrace
    reraise WrapperError, [exception: exception], stacktrace
end

round(number)

round(float()) :: integer()
round(value) :: value when value: integer()

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

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

Примеры

iex> round(5.6)
6

iex> round(5.2)
5

iex> round(-9.9)
-10

iex> round(-9)
-9

self()

self() :: pid()

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

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

send(dest, message)

send(dest :: pid() | port() | atom() | {atom(), node()}, message) :: message when message: any()

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

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

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

Примеры

iex> send self(), :hello
:hello

sigil_C(term, modifiers) (макрос)

Обрабатывает сигил ~C.

Просто возвращает строку символов без экранирования символов и без интерполяции.

Примеры

iex> ~C(foo)
'foo'

iex> ~C(f#{o}o)
'f\#{o}o'

sigil_D(date, modifiers) (макрос)

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

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

Примеры

iex> ~D[2015-01-13]
~D[2015-01-13]

sigil_N(date, modifiers) (макрос)

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

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

Примеры

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) (макрос)

Обрабатывает сигил ~R.

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

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

Примеры

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

sigil_S(term, modifiers) (макрос)

Обрабатывает сигил ~S.

Просто возвращает строку без экранирования символов и без интерполяций.

Примеры

iex> ~S(foo)
"foo"

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

sigil_T(date, modifiers) (макрос)

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

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

Примеры

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

sigil_W(term, modifiers) (макрос)

Обрабатывает сигил ~W.

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

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

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

Примеры

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

sigil_c(term, modifiers) (макрос)

Обрабатывает сигил ~c.

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

Примеры

iex> ~c(foo)
'foo'

iex> ~c(f#{:o}o)
'foo'

iex> ~c(f\#{:o}o)
'f\#{:o}o'

sigil_r(term, modifiers) (макрос)

Обрабатывает сигил ~r.

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

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

Примеры

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

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

sigil_s(term, modifiers) (макрос)

Обрабатывает сигил ~s.

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

Примеры

iex> ~s(foo)
"foo"

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

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

sigil_w(term, modifiers) (макрос)

Обрабатывает сигил ~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]

spawn(fun)

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)

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

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

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

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

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

Примеры

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

spawn_link(fun)

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)

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)

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)

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

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

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

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

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

Примеры

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

struct(struct, fields \\ [])

struct(module() | struct(), Enum.t()) :: struct()

Создаёт и обновляет структуры.

Аргумент struct может быть атомом (который определяет defstruct) или самой структурой. Второй аргумент — это любой перечисляемый объект struct, который выводит пары ключ-значение в виде кортежей из двух элементов во время перечисления.

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

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

Примеры

defmodule User do
  defstruct name: "john"
end

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

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

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

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

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

struct!(struct, fields \\ [])

struct!(module() | struct(), Enum.t()) :: struct() | no_return()

Аналогично struct/2, но проверяет корректность ключей.

Функция struct!/2 имитирует поведение структур на этапе компиляции. Это означает, что:

  • при построении структуры, как в struct!(SomeStruct, key: :value), она эквивалентна %SomeStruct{key: :value} и, следовательно, эта функция будет проверять, принадлежит ли каждая пара ключ-значение структуре. Если структура требует какой-либо ключ через @enforce_keys, то это будет проверено также;

  • при обновлении структуры, как в struct!(%SomeStruct{}, key: :value), она эквивалентна %SomeStruct{struct | key: :value} и, следовательно, эта функция будет проверять, принадлежит ли каждая пара ключ-значение структуре. Однако, обновление структур не требует проверки ключей, так как ключи проверяются только при построении;

throw(term)

throw(term()) :: no_return()

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

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

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

tl(list)

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([])
#=> ** (ArgumentError) argument error

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

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

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

to_charlist(term) (макрос)

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

Примеры

iex> to_charlist(:foo)
'foo'

to_string(term) (макрос)

Преобразует аргумент в строку в соответствии с протоколом String.Chars.

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

Примеры

iex> to_string(:foo)
"foo"

trunc(number)

trunc(value) :: value when value: integer()
trunc(float()) :: integer()

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

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

Примеры

iex> trunc(5.4)
5

iex> trunc(-5.99)
-5

iex> trunc(-5)
-5

tuple_size(tuple)

tuple_size(tuple()) :: non_neg_integer()

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

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

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

Примеры

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

unless(condition, clauses) (макрос)

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

Этот макрос вычисляет и возвращает блок do переданный во втором аргументе, если clause вычисляется как true. В противном случае, возвращает значение блока 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) (макрос)

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

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

update_in(opts[:foo][:bar], &(&1 + 1))

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

update_in(opts, [: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)

update_in(Access.t(), [term(), ...], (term() -> term())) :: Access.t()

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

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

Примеры

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

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

use(module, opts \\ []) (макрос)

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

При вызове:

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

В этом примере ExUnit.Case.__using__/1 вызывается со списком ключевых слов [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) (макрос)

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

Аргументом может быть нецитируемая переменная или стандартная форма кортежа {name, meta, context}.

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

left |> right (макрос)

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

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

Примеры

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

Вторая проблема заключается в том, что оператор |> работает с вызовами. Например, когда вы пишете:

"Hello" |> some_function()

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

Учитывая анонимную функцию:

fun = fn x -> IO.puts(x) end
fun.("Hello")

Это не сработает, так как вместо этого будет пытаться вызвать локальную функцию fun:

"Hello" |> fun()

Это работает:

"Hello" |> fun.()

Как можно заметить, оператор конвейера |> сохраняет ту же семантику, что и в случае без оператора конвейера, поскольку оба требуют обозначения fun.(...).

left || right (макрос)

Предоставляет оператор короткого замыкания, который вычисляет и возвращает второе выражение только в том случае, если первое не вычисляется как true (т.е., оно либо 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.5.3/Kernel.html

Spec-Zone.ru

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