5

我不明白 Elixir 中等号的确切含义。不清楚的是,它看起来像是赋值和模式匹配操作的混合。

iex(1)> x=4
4
iex(2)> y=5
5
iex(3)> 3=y
** (MatchError) no match of right hand side value: 5

iex(3)> y=3
3
iex(4)> y=x
4

我知道在 Elixir 中,等号运算符意味着将 = 符号的左侧与右侧匹配。前两行对我来说很有意义。x 和 y 是未绑定的变量,因此它们可以匹配任何东西。它们在匹配时被绑定。因此,我理解第三行。你不能将 3 与 5 匹配。

我开始失去理智的地方是为什么执行最后两行而没有给出相同的错误。看起来等号只是重新成为赋值运算符。

我试图在没有完全理解的情况下接受这种行为作为一个事实,并试图在语言学习中走得更远。但是由于模式匹配是 Elixir 的核心机制之一,我一直处于锁定状态,觉得我应该回到这个最初的问题。在我完全理解“=”符号到底发生了什么以及逻辑是什么之前,我不会再进一步​​了。

4

3 回答 3

6

等号的意思是:“尝试将右侧的表达式值拟合到左侧的形状并相应地分配值”。所以左边和右边是不同的,你不能切换它们。在右侧,所有变量都必须绑定,因为它是一个表达式。在左侧,即使您使用已经绑定的变量,它们也会被重新分配。

所以第一件事是在右边你可以有任何你想要的表达:

{:error, :enoent} = File.open("foo")

但你不能在左边有一个表达式:

iex(1)> File.open("foo") = {:error, :enoent}
** (CompileError) iex:1: cannot invoke remote function File.open/1 inside match

的情况下

y=3
5=y # y gets evaluated to 3 and then you pattern match 3=5

它失败了。但你可以做

y=3
y=5 # y gets reassigned.

在左侧,您只能具有可能是任意嵌套数据结构的“形状”:

[a, b, %{"a" => {1, c}}] = [1, 2, %{"a" => {1, 2}]
# c is now assigned value of 2

因此模式匹配用于解构数据或断言某些条件,例如

case File.open("foo") do
  {:ok, contents} -> enjoy_the_file(contents)
  {:error, reason} -> print_error(reason)
end

或者,如果您想断言数据库中只有一个实体,而不是首先断言它存在,然后只有一个实体可以进行模式匹配:

[entity] = Repo.all(query)

如果你想断言列表中的第一个值是一个,你可以模式匹配:

[1 | rest] = [1, 2, 3]

模式匹配时有一些陷阱。例如这个:

%{} = %{a: "a"}

将匹配,因为左侧的形状是地图,您不需要任何其他内容,因此任何地图都会匹配。但是,这不匹配:

%{a: "a"} = %{}

因为左边的形状说“给我一张带有 atom 键的地图:a

如果你想匹配一个变量,你可以这样写:

a = 1
{a, b} = {2, 3}

但这将分配a值 2。相反,您需要使用 pin 运算符:

a = 1
{^a, b} = {2, 3} #match fails

我在这个答案中写了更多关于 pin 运算符的内容:什么是“pin”运算符,并且 Elixir 变量是可变的?

于 2016-06-24T14:59:39.167 回答
3

我开始失去理智的地方是为什么执行最后两行而没有给出相同的错误。看起来等号只是重新成为赋值运算符。

这是因为左侧的变量名与其在 Elixir 中的值匹配。相反,该变量被重新分配给右侧的匹配值。

这与 Erlang 的不同之处在于您所期望的会发生什么:

1> X = 4.
4
2> Y = 5.
5
3> 3 = Y.
** exception error: no match of right hand side value 5
4> Y = 3.
** exception error: no match of right hand side value 3
5> Y = X.
** exception error: no match of right hand side value 4

要在 Elixir 中获得相同的行为,您需要在左侧按值匹配的每个变量上使用“pin”运算符:

iex(1)> x = 4
4
iex(2)> y = 5
5
iex(3)> 3 = y
** (MatchError) no match of right hand side value: 5

iex(3)> ^y = 3
** (MatchError) no match of right hand side value: 3

iex(3)> ^y = x
** (MatchError) no match of right hand side value: 4
于 2016-06-24T14:58:01.763 回答
0

两种情况:

1)Left hand side占位符/变量

  • 任何正确的都会被分配

例子:

x = 5
y = x (y gets value 5)
x = y (x gets value 5)

2)Left hand side价值

  • 匹配右手值/变量的值

例子:

5 = x (Error: as x is undefined)
x = 5
5 = x (5 matches with 5)
6 = x (Error: 6 is not matches with 5)
于 2016-10-17T16:34:01.097 回答