简体   繁体   English

Elixir 中等号的确切含义是什么?

[英]What is the exact meaning of the equal sign in Elixir?

I don't get what exactly means the equal sign in Elixir.我不明白 Elixir 中等号的确切含义。 What is unclear is that it looks like a mix between assignment and a pattern matching operation.不清楚的是,它看起来像是赋值和模式匹配操作的混合体。

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

I understand that in Elixir, the equals operator means to match the left side of the = sign to the the right side.我知道在 Elixir 中,等号运算符意味着将 = 符号的左侧与右侧匹配。 First two lines make sense to me.前两行对我来说很有意义。 x and y are unbound variables, hence they could match anything. x 和 y 是未绑定的变量,因此它们可以匹配任何内容。 They are bound as they match.它们在匹配时被绑定。 Consequently, I understand the third line.因此,我理解第三行。 You can't match 3 with 5.你不能将 3 与 5 匹配。

Where I start to loose my head is why the hell the two last lines are executed without giving the same error.我开始松懈的地方是为什么最后两行在没有给出相同错误的情况下执行。 It looks like the equal sign is back to being an assignment operator only.看起来等号又回到了仅作为赋值运算符的状态。

I've try to accept this behaviour as a fact without full understanding and tried to go further in the learning of the language.我试图在没有完全理解的情况下接受这种行为,并试图在语言学习中走得更远。 But as pattern matching is one of the core mechanism of Elixir, I'm constantly lock and feel I should go back to this original question.但是由于模式匹配是 Elixir 的核心机制之一,我不断锁定并觉得我应该回到这个原始问题。 I will not go any further before I fully understand what exactly happens with the "=" sign and what is the logic.在我完全理解“=”符号究竟发生了什么以及逻辑是什么之前,我不会再进一步​​了。

The equals sign means: "try to fit the value of expression on the right to the shape on the left and assigning values accordingly".等号的意思是:“尝试将右侧的表达式值与左侧的形状相匹配并相应地分配值”。 So left and right side are different and you cannot switch them.所以左边和右边是不同的,你不能切换它们。 On the right side all variables have to be bound, because it is an expression.在右侧,所有变量都必须绑定,因为它是一个表达式。 On the left side even if you use variables that are already bound they will be reassigned.在左侧,即使您使用已经绑定的变量,它们也会被重新分配。

So first thing is that on the right you can have any expression your want:所以第一件事是在右边你可以有任何你想要的表达:

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

but you can't have an expression on the left side:但是左侧不能有表达式:

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

In case of的情况下

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

and it fails.它失败了。 But you can do但是你可以做

y=3
y=5 # y gets reassigned.

On the left hand side you can only have "shape" which may be arbitrarly nested datastructure:在左侧,您只能拥有可以任意嵌套数据结构的“形状”:

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

So pattern matching is used to either destructure data or to assert some condition like因此,模式匹配用于解构数据或断言某些条件,例如

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

or if you want to assert that there is only one entity in the database instead of firstly asserting it exists and then that there is only one you can pattern match:或者,如果您想断言数据库中只有一个实体,而不是首先断言它存在,然后断言只有一个实体,您可以进行模式匹配:

[entity] = Repo.all(query)

If you want to assert that the first value in a list is one, you can pattern match:如果你想断言列表中的第一个值是一个,你可以模式匹配:

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

There are some gotchas when pattern matching.模式匹配时有一些问题。 For example this:例如这个:

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

will match, because shape on the left side is a map and you don't require anything more so any map will match.将匹配,因为左侧的形状是一张地图,您不需要更多内容,因此任何地图都将匹配。 However this won't match:但是,这不匹配:

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

because shape on the left says "give me a map with a key of atom :a .因为左边的形状说“给我一张带有 atom 键的地图:a

If you would like to match on a variable you may write something like this:如果你想匹配一个变量,你可以这样写:

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

but this will assign a the value 2. Instead you need to use pin operator:但是这将分配a值2。相反,你需要使用PIN操作:

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

I wrote more about pin operator in this answer: What is the "pin" operator for, and are Elixir variables mutable?我在这个答案中写了更多关于 pin 运算符的内容: “pin”运算符是什么,Elixir 变量是否可变?

Where I start to loose my head is why the hell the two last lines are executed without giving the same error.我开始松懈的地方是为什么最后两行在没有给出相同错误的情况下执行。 It looks like the equal sign is back to being an assignment operator only.看起来等号又回到了仅作为赋值运算符的状态。

That's because a variable name on the left side is not matched by its value in Elixir.那是因为左侧的变量名与其在 Elixir 中的值匹配。 Instead, the variable is reassigned to the matching value on the right side.相反,变量被重新分配给右侧的匹配值。

This is different from Erlang where exactly what you expect happens:这与 Erlang 不同,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

To get the same behavior in Elixir, you need to use the "pin" operator on each variable you want to match by value on the left side:要在 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

Two cases:两种情况:

1) Left hand side is placeholder/variable : 1) Left hand side占位符/变量

  • Whatever in right will get assigned任何正确的都会被分配

Example:例子:

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

2) Left hand side is value 2) Left hand side价值

  • Match with the right hand value/variable's value右手值/变量值匹配

Example:例子:

5 = x (Error: as x is undefined)
x = 5
5 = x (5 matches with 5)
6 = x (Error: 6 is not matches with 5)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM