Дружественное использование состояний в Эликсире

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

В других языках вы можете сохранить его в переменной или что-то в этом роде, например, useState в React и т. д., но поскольку Эликсир неизменяем, нам нужен другой способ его хранения. У нас есть Агент, как упоминалось выше, но у нас есть два других способа управления состояниями в Эликсире:

  • GenServer инкапсулирует состояние и обеспечивает синхронизацию и асинхронные вызовы для поддержки перезагрузки кода и т. д.
  • У нас есть процесс Task с асинхронными вычислительными единицами, которые позволяют порождать процесс и потенциально получать его результат позже.

Но для простого управления состоянием мы можем использовать Агент. Хорошо, но как мы можем использовать Агент для управления состояниями? Вот код агента, умножающего число на 2:

Вы можете спросить себя, что это за функции, и я подробно объясню каждую из них:

  • Первым делом объявляем наш модуль, который я назвал Double, можете называть как хотите, а потом называем use Agent что это значит? Вызов use генерирует функцию child_spec с конфигурацией по умолчанию.
  • Затем у нас есть функция start_link, и эта функция необходима, потому что вы запускаете своего агента и устанавливаете начальное значение, и именно там вы будете хранить информацию о состоянии. Затем у нас есть функция Agent.start_link, которая инициализирует агента, и в параметрах вы передаете анонимную функцию, передавая начальное_значение агента. Здесь мы устанавливаем имя __MODULE__, это имя модуля, чтобы помочь при вызове других функций, потому что, если мы не передаем это, нам нужно будет передать PID агента.

Прежде чем перейти к следующей теме, поговорим об анонимных функциях. Так же, как имя подразумевает анонимную функцию, это просто обычная функция, но без имени, вы можете получать параметры и делать все, что делаете в обычной функции, но у нее не будет имени, вы будете использовать ее в основном, когда вам нужно передать функцию к другой, то вы используете анонимные функции. Мы объявляем анонимные функции со следующим синтаксисом: fn x, y -> x + y endэто просто добавляет параметры x и y, -> это похоже на do в функциях, и ему нужно и end . Очень просто нет? Перейдём к следующей теме

  • Здесь у нас есть функция значения, которая представляет собой простую функцию, которая возвращает число, которое хранится в этом агенте с функцией Agent.get, эта функция ожидала имя модуля и то, что вы хотите восстановить. Чтобы восстановить значение, хранящееся в агенте, мы используем этот синтаксис & &1, который принимает сохраненное значение.
  • И последнее, но не менее важное: функция double берет initial_value, а затем удваивает его. В этой функции мы используем функцию Agent.update, которая принимает текущее значение состояния и преобразует его в желаемое значение, в нашем случае мы берем initial_value с сокращением, чтобы получить текущее значение состояния & &1, а затем умножаем его на 2.

Итак, давайте проверим это?

iex> Double.start_link(5)
{:ok, #PID<0.152.0>} # Note the PID is not always the same
iex> Double.value()
5
iex> Double.double
:ok
iex> Double.value()
10

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