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

3

我目前正在学习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

上述代码应该作为一个完全功能的状态机工作。 我将在下面粘贴一些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语句的结构副本,遵循正确的函数模式...但是它如何在不直接修改它的情况下“覆盖”当前状态呢?
非常感谢!

4
刚刚意识到已经有一个包含更详细答案的现有问题:Elixir变量真的是不可变的吗? - Sheharyar
1
另一个有趣的Q/A,可能会澄清更多事情: Elixir: 允许重新绑定变量背后的原因 - Sheharyar
1个回答

5
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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接