Дружественное использование состояний в Эликсире
Поскольку Эликсир неизменен, вы можете подумать, как неизменяемый язык может работать с состояниями, которые постоянно меняются? Все просто: у нас есть Агент, который представляет собой не что иное, как оболочку состояния.
В других языках вы можете сохранить его в переменной или что-то в этом роде, например, 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
Итак, здесь вы узнали, что такое агент и как он работает, в непринужденной форме.