Logo
Section 1 / 10

让两件事匹配

了解 Elixir 的模式匹配。

导入

让两件事匹配

了解 Elixir 的模式匹配。

模式匹配简介

控制程序流程意味着决定哪些函数和表达式将被执行。在命令式语言中,主要依赖 if 等条件结构,但在函数式编程的世界里,模式匹配 扮演着核心角色。然而,模式匹配常常被误解,对初学者来说也较难理解,这也是本章一半内容都用于深入理解它的原因。

我们随后将使用模式匹配来决定调用哪个函数,从而实现一种控制流机制。到本章结束时,我们将看到一些 Elixir 中的控制流结构,它们利用逻辑表达式和模式匹配来简化常见的代码表达。让我们迈出第一步,学习模式匹配。

Elixir 中的模式匹配贯穿于我们编写的每一行代码。它可用于变量赋值、解构数据,以及决定调用哪个函数。模式匹配的基础是尝试使两边相匹配,当无法匹配时,会执行某种操作。

使用 = 进行模式匹配

我们从 = 操作符开始学习模式匹配。当两边无法匹配时,该操作符会抛出 MatchError,导致程序停止执行。如果两边能够匹配,则程序继续运行。下面我们通过实际例子逐步了解其工作原理。打开一个 IEx 会话,输入以下模式匹配表达式。课程末尾提供了一个终端,供你测试所有这些命令。

1iex> 1 = 1 2# 输出 -> 1 3 4iex> 2 = 1 5# 输出 -> ** (MatchError) no match of right hand side value: 1 6 7iex> 1 = 2 8# 输出 -> ** (MatchError) no match of right hand side value: 2

1 = 1 可以匹配,但 2 = 1 和 1 = 2 无法匹配,因为它们是不同的数字。

让我们尝试使用变量进行一个熟悉的表达式:

1iex> x = 1 2# 输出 -> 1

这看起来像普通的变量赋值,但实际上并非如此;这是模式匹配。Elixir 通过将值 1 绑定到变量 x,使两边相等。再来看一个不同的例子:

1iex> 1 = x 2# 输出 -> 1

此时值在左边,变量在右边,这是一个合法的 Elixir 表达式。之前我们说过 x = 1,现在值 1 已绑定到变量 x。当我们输入 1 = x 时,Elixir 会检查左边的值是否等于右边的值。如果两边相等,表达式就有效。再看一个例子:

1iex> 2 = x 2# 输出 -> ** (MatchError) no match of the right hand side value: 1

Elixir 试图匹配两边。右边变量 x 的值是数字 1,而数字 2 不等于 1,因此抛出 MatchError。判断 = 操作符两边是否相等的过程就是模式匹配。如果你第一次接触这种机制,可能会感到难以理解。为了帮助我们理解背后的运行机制,下面是一个类比的命令式写法:

1if (2 == x) 2 2; 3else 4 raise MatchError;

如果 x 不等于 2,就会抛出错误。

重新绑定与 ^ 操作符

现在我们来看看如果交换前面表达式的两边会发生什么:

1iex> x = 2 2# 输出 -> 2

现在变量 x 出现在左边,行为发生了变化。Elixir 会匹配任意内容,并将右边表达式的值绑定到变量上。我们可以为已有变量绑定新值,这称为重新绑定。Elixir 将数字 2 绑定到 x,使两边匹配。如果我们想避免重新绑定,可以使用钉住操作符:^。这个操作符允许我们使用变量的当前值来进行匹配,而不是重新绑定。请自己尝试一下:

1iex> x = 2 2# 输出 -> 2 3 4iex> ^x = 2 5# 输出 -> 2 6 7iex> ^x = 1 8# 输出 -> ** (MatchError) no match of right hand side value: 1

使用钉住操作符后,Elixir 会使用变量的当前值进行匹配。通过这个简单的 = 操作符,我们可以检查两边是否匹配。如果不匹配,程序将以匹配错误终止执行。对于习惯了其他编程范式中变量赋值的人来说,意识到 = 并不只是用于绑定变量可能需要一点时间。为了帮助过渡,我们可以借用代数中的类比:如果 x = 1,那么 1 = x 也是成立的。模式匹配远不止于此,我们还可以用来进行各种检查,解构不同数据类型的值,从而解决更复杂的问题。

使用变量和函数

从字符串和元组中解包值