Elixir基础笔记(三)—— 模式匹配

在这篇文章中将会提到Elixir中最常见的功能也是最核心的功能——模式匹配。让我们一起来看看吧。

匹配操作符

在之前的介绍中我们已经见到过了=操作符的用法

1
2
3
4
iex> x = 1
1
iex> x
1

其实,在Elixir中=操作符实际上叫做匹配操作符。我们看一下下面的例子

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

注意,上面的1 = x是合法的表达式,由于左边和右边都等于1所以他们匹配成功,当有一侧的值不匹配时会抛出MatchError的错误

为定义过的变量只能在左侧进行匹配,在下面的例子中由于unknown变量没有定义,Elixir将会假设你调用函数unknown/0,然而这个函数也没有定义,所以引发错误。

1
2
iex> 1 = unknown
** (CompileError) iex:1: undefined function unknown/0

模式匹配

匹配操作符不仅仅是用来匹配简单的值,在解构复杂的数据类型时同样很有用。

1
2
3
4
5
6
iex> {a, b, c} = {:hello, "world", 42}
{:hello, "world", 42}
iex> a
:hello
iex> b
"world"

当左右不匹配的时候会抛出错误。比如当两边的元组长度不一致的时候

1
2
iex> {a, b, c} = {:hello, "world"}
** (MatchError) no match of right hand side value: {:hello, "world"}

还有当数据类型不一致的时候

1
2
iex> {a, b, c} = [:hello, "world", 42]
** (MatchError) no match of right hand side value: [:hello, "world", 42]

更有趣的是我们可以匹配特定的值,下面的例子表示只有当两边的元组都以:ok原子开头的时候才会匹配

1
2
3
4
5
6
7
iex> {:ok, result} = {:ok, 13}
{:ok, 13}
iex> result
13

iex> {:ok, result} = {:error, :oops}
** (MatchError) no match of right hand side value: {:error, :oops}

除了元祖外,我们当然也可以模式匹配列表

1
2
3
4
iex> [a, b, c] = [1, 2, 3]
[1, 2, 3]
iex> a
1

匹配列表的时候也支持headtail

1
2
3
4
5
6
iex> [head | tail] = [1, 2, 3]
[1, 2, 3]
iex> head
1
iex> tail
[2, 3]

同样的,空列表无法匹配[head | tail]

1
2
iex> [h | t] = []
** (MatchError) no match of right hand side value: []

[head | tail] 除了可以用来匹配之外,还可以用来向列表首部添加内容。

1
2
3
4
iex> list = [1, 2, 3]
[1, 2, 3]
iex> [0 | list]
[0, 1, 2, 3]

指针操作符

变量可以在Elixir中被重新绑定

1
2
3
4
iex> x = 1
1
iex> x = 2
2

使用指针操作符^可以进行匹配已经存在的变量的值而不是进行重新绑定

1
2
3
4
5
6
7
8
9
10
iex> x = 1
1
iex> ^x = 2
** (MatchError) no match of right hand side value: 2
iex> {y, ^x} = {2, 1}
{2, 1}
iex> y
2
iex> {y, ^x} = {2, 2}
** (MatchError) no match of right hand side value: {2, 2}

其他

如果一个变量在模式匹配中出现多次,那么他们的值应该是全部一致的。

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

有时候我们只关心一个数据结构中的一部分,我们可以使用下划线_来忽略其余的地方。

1
2
3
4
iex> [h | _] = [1, 2, 3]
[1, 2, 3]
iex> h
1