关于Elixir的所有内容,我都认为分配应该被认为是模式匹配。如果是这样,那么为什么x = x + 1在Elixir中起作用?没有x = x + 1的x值。
答案 0 :(得分:6)
关于Elixir的所有内容,我都认为应该将分配视为模式匹配。
在Elixir中,=
被称为模式匹配运算符,但其工作方式与Erlang中的模式匹配运算符不同。这是因为在Elixir中变量不是像在Erlang中那样是单一分配。这是Erlang的工作方式:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> X = 15.
15
2> X = 100.
** exception error: no match of right hand side value 100
3> X.
15
4>
因此,在Erlang中这将失败:
4> X = X + 1.
** exception error: no match of right hand side value 16
使用Erlang的单次分配,事情很简单:因为X已经有一个值,所以行X = X + 1
不能试图给X赋一个新值,因此该行是对模式进行匹配的尝试({{ 1}}),它将始终失败。
另一方面,Elixir中的变量不是单个赋值:
15 = 15 + 1
在Elixir中变量不是单一赋值这一事实意味着在编写时Elixir需要做出选择:
Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> x = 15
15
iex(2)> x = 100
100
iex(3)> x
100
iex(4)>
选择1)第二行是否应解释为对x = 10
x = x + 1 #or even x = 15
的赋值?
选择2)第二行是否应该解释为尝试模式匹配(即x
)?
Elixir具有选择1。这意味着使用Elixir中的所谓模式匹配运算符实际执行模式匹配会更加困难:您必须将pin运算符(10 = 11
)与match运算符结合使用(^
)
=
现在,第二行将始终失败。如果您想在不使用pin运算符的情况下执行模式匹配,还有一种技巧在某些情况下会起作用:
x = 10
^x = x + 1
在第二行中,将变量放在右侧。我认为规则可以这样表示:在模式匹配运算符(x = 10
12 = x
)的右侧,总是对变量求值,即用其值替换。始终在左侧分配变量-除非使用pin运算符,否则在这种情况下,固定变量将替换为其当前值,然后在右侧进行模式匹配。结果,将Elixir的=
运算符称为混合分配/模式匹配运算符可能更准确。
答案 1 :(得分:5)
您可以想象x = x + 1
被编译器重写为x2 = x1 + 1
之类的东西。
这非常接近其工作方式。这不是我在这里使用的简单索引号,但是概念是相同的。 BEAM看到的变量是不可变的,并且在该级别上没有重新绑定。
在Erlang程序中,您会发现像X2 = X1 + 1
这样的代码。两种方法都有缺点。 JoséValim在设计Elixir时做出了有意识的选择,允许重新绑定变量,并且他写了一篇博客文章,比较了这两种方法以及存在以下风险的各种错误:
http://blog.plataformatec.com.br/2016/01/comparing-elixir-and-erlang-variables/
答案 2 :(得分:4)
在模式匹配期间,匹配右边的值被分配到左侧匹配的变量:
iex(1)> {x, y} = {1, 2}
{1, 2}
iex(2)> x
1
iex(3)> y
2
在右侧,使用匹配之前的变量值。在左侧,设置了变量。
您可以通过^
pin operator强制左侧也使用变量的值:
iex(4)> x = 1
1
iex(5)> ^x = x + 1
** (MatchError) no match of right hand side value: 2
此操作失败,因为它等效于1 = 1 + 1
,这是您期望的失败条件。