我读过有关Elixir的所有内容都说应该将赋值视为模式匹配。如果是这样,为什么x = x + 1在Elixir中起作用?没有x的值,x = x + 1。
我读过有关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赋值,因此该行是模式匹配的尝试(15 = 15 + 1
),它总是会失败。
另一方面,在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)>
Elixir中变量不是单一赋值的事实意味着Elixir在您编写时需要做出选择:
x = 10
x = x + 1 #or even x = 15
选择1)第二行应该被解释为x
的赋值吗?
选择2)第二行是否应该被解释为模式匹配的尝试(即10 = 11
)?
Elixir选择选择1.这意味着实际上与Elixir中所谓的模式匹配运算符执行模式匹配更加困难:您必须将引脚运算符(^
)与匹配运算符(=
)结合使用:
x = 10
^x = x + 1
现在,第二行总是会失败。如果要在不使用pin运算符的情况下执行模式匹配,还有一种技巧可以在某些情况下使用:
x = 10
12 = x
在第二行中,您将变量放在右侧。我认为规则可以这样陈述:在模式匹配运算符(=
)的右侧,始终评估变量,即用它们的值替换。在左侧,变量总是分配给 - 除非使用了引脚操作符,在这种情况下,固定变量被其当前值替换,然后模式匹配右侧。因此,将Elixir的=
运算符称为混合赋值/模式匹配运算符可能更准确。
您可以想象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/
在模式匹配期间,匹配右侧的值将分配给左侧的匹配变量:
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
,这是你期望的失败条件。