Действительно ли структуры Elixir неизменяемы?

В настоящее время я изучаю Эликсир и читаю "Функциональная веб-разработка с помощью Эликсира, OTP и Феникса", и это отличная книга. Работая над главой конечного автомата, я придумал следующий код:

defmodule IslandsEngine.Rules do
  alias __MODULE__

  defstruct state: :initialized

  def new(), do: %Rules{}

  def check(%Rules{state: :initialized} = rules, :add_player), do:
    {:ok, %Rules{rules | state: :players_set}}

  def check(_state, _action), do: :error

end

Приведенный выше код должен работать как полнофункциональный конечный автомат. Я вставлю выше несколько команд iex:

iex(1)> alias IslandsEngine.Rules
IslandsEngine.Rules

iex(2)> rules = Rules.new()
%IslandsEngine.Rules{state: :initialized}

iex(3)> {:ok, rules} = Rules.check(rules, :add_player)
{:ok, %IslandsEngine.Rules{state: :players_set}}

iex(4)> rules.state
:players_set

Как видите, структура состояния изменилась с :initialized на :add_player. Отлично.

Мой вопрос: действительно ли структура state: неизменна? Я имею в виду, что метод check/1 возвращает копию структуры с оператором state: :players_set, который следует правильному функциональному шаблону... но как он «перезаписывает» текущий статус, не изменяя его напрямую?

Большое спасибо!


person Michele Riva    schedule 01.11.2018    source источник
comment
Только что понял, что существует существующий вопрос с ответами, которые охватывают это гораздо более подробно: Действительно ли переменные Elixir неизменяемы? ?   -  person Sheharyar    schedule 01.11.2018
comment
Еще один интересный вопрос/ответ, который может прояснить еще несколько вещей: разрешение повторной привязки переменных   -  person Sheharyar    schedule 01.11.2018


Ответы (1)


Структуры данных Elixir действительно неизменяемы. Но происходит следующее: вызовы функций возвращают совершенно новое значение (отличающееся от исходного в зависимости от вызванной вами функции).

Что касается «изменения значения переменной», это дополнительная функция на Elixir (поверх исходного Erlang языка). Значение переменной на самом деле не меняется, оно просто привязывается к новому. Старые автоматически удаляются сборщиком мусора Erlang VM.


Итак, в вашем примере:

# This returns a completely new `%Rules{}` struct and rebinds
# the `rules` variable to the new term
{:ok, rules} = Rules.check(rules, :add_player)
person Sheharyar    schedule 01.11.2018