等号的意思是:“尝试将右侧的表达式值拟合到左侧的形状并相应地分配值”。所以左边和右边是不同的,你不能切换它们。在右侧,所有变量都必须绑定,因为它是一个表达式。在左侧,即使您使用已经绑定的变量,它们也会被重新分配。
所以第一件事是在右边你可以有任何你想要的表达:
{: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 变量是可变的?