Spec-Zone.ru › Elixir 1.17

Исходный код Анонимные функции

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

Определение анонимных функций

Анонимные функции в Elixir ограничены ключевыми словами fn и end:

iex> add = fn a, b -> a + b end
#Function<12.71889879/2 in :erl_eval.expr/5>
iex> add.(1, 2)
3
iex> is_function(add)
true

В примере выше мы определили анонимную функцию, которая принимает два аргумента, a и b, и возвращает результат a + b. Аргументы всегда находятся слева от ->, а код, который необходимо выполнить, — справа. Анонимная функция хранится в переменной add.

Мы можем вызывать анонимные функции, передавая им аргументы. Обратите внимание, что для вызова анонимной функции требуется точка (.) между переменной и скобками. Точка делает ясным, когда вы вызываете анонимную функцию, хранящуюся в переменной add, в отличие от функции с именем add/2. Например, если у вас есть анонимная функция, сохраненная в переменной is_atom, нет неоднозначности между is_atom.(:foo) и is_atom(:foo) . Если бы обе использовали ту же синтаксическую конструкцию is_atom(:foo), единственный способ узнать фактическое поведение is_atom(:foo) заключался бы в просмотре всего кода до этого момента, чтобы найти возможное определение переменной is_atom . Такой поиск усложняет сопровождение, так как разработчикам нужно отслеживать дополнительный контекст при чтении и записи кода.

Анонимные функции в Elixir также идентифицируются по количеству принимаемых аргументов. Мы можем проверить арность функции с помощью is_function/2:

# check if add is a function that expects exactly 2 arguments
iex> is_function(add, 2)
true
# check if add is a function that expects exactly 1 argument
iex> is_function(add, 1)
false

Замыкания

Анонимные функции также могут получать доступ к переменным, которые находятся в области видимости во время определения функции. Это обычно называется замыканием, так как они «замыкаются» на своей области видимости. Давайте определим новую анонимную функцию, которая использует ранее определенную анонимную функцию add:

iex> double = fn a -> add.(a, a) end
#Function<6.71889879/1 in :erl_eval.expr/5>
iex> double.(2)
4

Переменная, присвоенная внутри функции, не влияет на окружающую среду:

iex> x = 42
42
iex> (fn -> x = 0 end).()
0
iex> x
42

Разделы и условия

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

iex> f = fn
...>   x, y when x > 0 -> x + y
...>   x, y -> x * y
...> end
#Function<12.71889879/2 in :erl_eval.expr/5>
iex> f.(1, 3)
4
iex> f.(-1, 3)
-3

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

iex> f2 = fn
...>   x, y when x > 0 -> x + y
...>   x, y, z -> x * y + z
...> end
** (CompileError) iex:1: cannot mix clauses with different arities in anonymous functions

Оператор захвата

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

iex> fun = &is_atom/1
&:erlang.is_atom/1
iex> is_function(fun)
true
iex> fun.(:hello)
true
iex> fun.(123)
false

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

iex> fun = &String.length/1
&String.length/1
iex> fun.("hello")
5

Вы также можете захватывать операторы:

iex> add = &+/2
&:erlang.+/2
iex> add.(1, 2)
3

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

iex> fun = &(&1 + 1)
#Function<6.71889879/1 in :erl_eval.expr/5>
iex> fun.(1)
2

iex> fun2 = &"Good #{&1}"
#Function<6.127694169/1 in :erl_eval.expr/5>
iex> fun2.("morning")
"Good morning"

&1 представляет собой первый аргумент, переданный в функцию. &(&1 + 1) выше эквивалентно fn x -> x + 1 end. Подробнее об операторе захвата & можно узнать в его документации.

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

← Предыдущая страница case, cond и if
Следующая страница → Бинарники, строки и списки символов

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

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

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

Spec-Zone.ru

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