【问题标题】:What is the exact meaning of the equal sign in Elixir?Elixir中等号的确切含义是什么?
【发布时间】:2016-10-27 05:02:14
【问题描述】:

我不明白 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 是未绑定的变量,因此它们可以匹配任何东西。它们在匹配时被绑定。因此,我理解第三行。 5 不能匹配 3。

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

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

【问题讨论】:

标签: functional-programming equals elixir elixir-iex


【解决方案1】:

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

所以首先你可以在右边有任何你想要的表达方式:

{: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"} = %{}

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

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

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

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

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

我在这个答案中写了更多关于 pin 运算符的内容:What is the "pin" operator for, and are Elixir variables mutable?

【讨论】:

  • 在陷阱中,指出%{} = %{a: :b} 将匹配,[] =[:a, :b] 将不匹配可能也很有用。但这可能超出了您的答案范围。 ¯_(ツ)_/¯
  • 感谢您的深入解释。我喜欢这种形状和表达方式的隐喻,这让我更清楚。我还发现了这个bordeltabernacle.github.io/2015/12/31/…,它帮助我走得更远。
  • 从上面提到的帖子中,尤其是 Erlang 的创建者 Joe Amstrong 的这句话,等号的工作方式更类似于代数中的 = 符号(想想 x +5 = 10)。
【解决方案2】:

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

这是因为左侧的变量名与其在 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

【讨论】:

  • 因此 pin 运算符强制等号成为仅匹配运算符。没有引脚,它是一个匹配和分配。对吗?
【解决方案3】:

两种情况:

1) Left hand side占位符/变量

  • Whatever 将被分配

例子:

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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-14
    • 1970-01-01
    • 2017-04-19
    • 2011-05-06
    • 2013-07-22
    • 2010-11-05
    相关资源
    最近更新 更多