Elixir现有变量中Struct操作疑问:两段代码为何表现不同?
Elixir 新手疑问:两段灯泡代码行为差异解析
核心原因是Elixir的数据不可变特性——所有数据结构一旦创建就无法修改,函数返回的是新的结构,原变量不会被改变。
第一段代码分析
第一段代码的turn_on和turn_off函数,每次调用都会返回一个新的Bulb结构体实例,但原bulb变量始终保持初始的:on状态:
defmodule Bulb do defstruct [:state] def turn_on(bulb = %Bulb{}) do %{bulb | state: :on} end def turn_off(bulb = %Bulb{}) do %{bulb | state: :off} end end bulb = %Bulb{state: :on} # --> %Bulb{state: :on} bulb |> Bulb.turn_off() # --> 返回新的%Bulb{state: :off},但原bulb还是:on bulb |> Bulb.turn_on() # --> 基于原bulb(:on)返回新的%Bulb{state: :on}
这里两次调用都是基于原始的bulb变量值生成新实例,所以看起来“行为一致”——每次调用都是对初始状态的操作。
第二段代码的问题
第二段的switch_bulb函数逻辑是对的,但你没有把函数返回的新实例赋值给原变量:
defmodule Bulb do defstruct [:state] def switch_bulb(bulb = %Bulb{}) do case bulb do %{state: :off} -> %{bulb | state: :on} %{state: :on} -> %{bulb | state: :off} end end end bulb = %Bulb{state: :on} # --> %Bulb{state: :on} bulb |> Bulb.switch_bulb() # --> 返回新的%Bulb{state: :off},但原bulb还是:on bulb |> Bulb.switch_bulb() # --> 再次基于原bulb(:on)返回新的%Bulb{state: :off}
两次调用switch_bulb都是用的初始状态的bulb,所以每次都返回:off,看起来没有“切换”效果。
重新赋值后的正常行为
当你把函数返回的新实例重新赋值给bulb变量时,每次调用都是基于上一次的新状态操作:
defmodule Bulb do defstruct [:state] def switch_bulb(bulb = %Bulb{}) do case bulb do %{state: :off} -> %{bulb | state: :on} %{state: :on} -> %{bulb | state: :off} end end end bulb = %Bulb{state: :on} # --> %Bulb{state: :on} bulb = bulb |> Bulb.switch_bulb() # --> 新实例赋值给bulb,现在bulb是:off bulb = bulb |> Bulb.switch_bulb() # --> 基于当前bulb(:off)返回:on,再赋值给bulb
这时候变量bulb每次都指向新的结构体实例,所以实现了预期的切换效果。
内容的提问来源于stack exchange,提问作者blackened
相关产品推荐
相关产品推荐

