Elixir 结构真的是不可变的吗?

Mic*_*iva 3 erlang struct elixir-mix elixir elixir-iex

我目前正在学习 Elixir,并且正在阅读《使用 Elixir、OTP 和 Phoenix 进行功能性 Web 开发》,在我看来这是一本很棒的书。在状态机章节中,我想出了以下代码:

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
Run Code Online (Sandbox Code Playgroud)

上面的代码应该作为一个功能齐全的状态机工作。我将在上面粘贴一些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
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,状态结构已从 更改:initialized:add_player。伟大的。

我的问题是:state:struct 真的是不可变的吗?我的意思是,该方法check/1返回带有语句的结构副本state: :players_set,该语句遵循正确的功能模式......但是它如何“覆盖”当前状态而不直接修改它?

多谢!

She*_*yar 5

Elixir 数据结构确实是不可变的。但发生的情况是函数调用返回一个全新的值(该值与原始值不同,具体取决于您调用的函数)。

至于“改变变量的值”,这是(相对于原始语言)的一个附加功能。变量的值实际上并没有改变,它只是重新绑定到新的值。旧的会被自动垃圾收集ElixirErlangErlang VM.


所以在你的例子中:

# This returns a completely new `%Rules{}` struct and rebinds
# the `rules` variable to the new term
{:ok, rules} = Rules.check(rules, :add_player)
Run Code Online (Sandbox Code Playgroud)