Elixir 简明笔记(三)--- 模式匹配

函数式语言的一大特点就是使用模式匹配来做条件判断。Elixir甚至可以使用模式匹配来替代 if else 这些传统编程语言的控制结构。模式匹配对于Elixir至关重要,那么到底什么是模式匹配呢?

赋值号?等号?模式匹配号?

稍微有一点编程经验的人都会知道“=”这个符号是赋值符号,左边表示一个变量,右边是一个表达式或者值,将右边的值或表达式求值的结果赋予左边的变量。刚开始学编程的时候,都会强调赋值号与数学中的等号的差别。

可是在elixir中,你又得忘掉编程中的赋值号,重新拾起遗忘的数学等号。因为Elixir并没有赋值的概念,“=”也不是赋值号。Elixir中的“=”号是一个模式匹配符号。

变量绑定

=号是一个模式匹配符号,匹配成功将会进行绑定。请看下面的例子:

iex(1)> x = 1
1
iex(2)> x
1
iex(3)>

上述代码中,在x=1这个表达式中,左边的x是一个变量(实际上很多函数式语言的变量都是不可变的量,elixir的“变量”也是不变的)。右边的 1 是一个数值。表达式的含义是进行变量绑定。将1的值绑定给变量x,所以输入x的时候,对x求值等于1

也许你不以为然,变量绑定和赋值有什么差别呢?那么请看下面的语句:

iex(1)> x = 1
1
iex(2)> x
1
iex(3)> 1 = x
1
iex(4)> x
1
iex(5)>

常见的传统编程语言可不会出现1=x这样的表达式。实际上,Elixir中的=和数学上的等号概念类似,左边等于右边,右边等于左边,那么表达式就不会报错。当然,对于变量,可以重新绑定:

iex(1)> x = 1
1
iex(2)> x
1
iex(5)> x = 2
2
iex(6)> x
2

这个过程其实并没有改变变量x的值,而只是对x进行了重新的绑定。效果类似改变了值。

模式,匹配

既然知道了=是模式匹配符号,而不是等号,那上面为什么在说变量绑定?Elixir中的模式匹配英文是Pattern Match。可以理解为通过某个模式进行匹配,就像使用正则表达式这样的pattern对字符串进行匹配一样。一旦匹配成功,就会对匹配的项进行变量绑定。从匹配到绑定整个过程称之为模式匹配。有点拗口,贵在理解啦。

模式匹配,就必须先知道模式。=符号左边表示一个模式(pattern),右边则是一个表达式,或者一个数值。所谓的模式,也可以是一个数值,可以是一个变量,甚至也可以一些基本数据结构,例如列表(List),元组(Tuple),类字典(Dicionary)等。只要等号左右两边的数据类型和结构相同,则可以匹配。

从最简单的开始吧。前面的例子,我们见识了变量的模式匹配

iex(8)> a = 1
1

模式a和数值1匹配,匹配成功,将右边的数值和左边的模式变量a进行绑定。

iex(8)> a = 1
1
iex(9)> 1 = a
1

1=a,这个模式匹配表示含义是,左边的模式是数字1。右边是一个变量,该变量已经绑定了数值1,因此对a变量(表达式)求值,得到值1。表达式实际含义等价于1 = 1。右边的值1和左边的数字1值相等,匹配成功,然后进行变量绑定,可是右边的模式是数字1不是变量,就忽略了绑定过程。整个模式匹配成功。

在看下面的代码:

iex(8)> a = 1
1
iex(9)> 1 = a
1
iex(10)> 2 = a
** (MatchError) no match of right hand side value: 1
iex(10)>

表达式2=a发生了MatchError错误。这里模式匹配不成功,因为 2 = 1 明显不成了,匹配失败。前面的例子中,变量进行了重绑定,实际上是进行了重新的模式匹配。

模式匹配本质是对等式求值的过程,例如数学的等式中 x = y + 1。如果我们知道了y的值,自然可以通过数学表达式运算,求出x的值。模式匹配的本质就是针对右边的表达式或数字字面量求值,然后根据等式的原则,计算出左边的模式的值,再对左边进行变量的绑定。

模式匹配可以看成表达式运算,那么表达式肯定要是一类东西,而不是别的什么玩意了。例如x = y + 1中的 xy都是变量。如果是这样的表达式 fn x -> x end = y + 1。左边是一个匿名函数式,显然函数是不能进行加减运算的。这也就是为什么左边的变量或表达式称之为模式

复杂的例子

下面看几个复杂一点的模式匹配。

iex(12)> list = [1, 2, [3, 4, 5]]
[1, 2, [3, 4, 5]]
iex(13)> [a, b, c] = list
[1, 2, [3, 4, 5]]
iex(14)> a
1
iex(15)> b
2
iex(16)> c
[3, 4, 5]
iex(17)>

首先,有一个内嵌列表的列表。表达式list=[1, 2, [3, 4, 5]]将列表和变量list进行匹配,这里列表可以看成一个整体,匹配成功,然后进行变量绑定,将变量list绑定成一个列表。

[a, b, c] = list表达式左边的模式也是一个列表,右边也是一个列表(同一类型),并且左右两边的列表都是三个项目元素(同一结构)。匹配成功,然后进行变量绑定。

通过这个例子,可以清楚的知道,模式匹配的模式和表达式或数值的结构必须要相同。即同一数据类型,同一结构类型。

模式可以是数值和变量,也可以是变量和数值的混合结构

iex(17)> list = [1, 2, 3]
[1, 2, 3]
iex(18)> [a, 2, c] = list
[1, 2, 3]
iex(19)> a
1
iex(20)> c
3
iex(21)> 2
2
iex(22)>

例子中,右边的模式中的结构和右边一致 ,并且第二个元素都是2,匹配成功,剩下的ac也可以匹配成功,进行变量绑定。

变量是可以重新绑定,但是在一次模式匹配中,变量只能绑定一次

iex(22)> [a, a] = [1, 1]
[1, 1]
iex(23)> [a, a] = [1, 2]
** (MatchError) no match of right hand side value: [1, 2]
iex(23)>

第二个表示中,含有两个a变量的列表在结构和数据类型都和左边相匹配,可是进行变量绑定的时候,a只能绑定一次,因此整个模式匹配过程失败。

想要重新绑定变量,只需要再进行一次模式匹配即可:

iex(23)> a = 1
1
iex(24)> [1, a] = [1, 2]
[1, 2]
iex(25)> a
2
iex(26)>

固定绑定

函数式本来追求的是不变,如果也想要变量绑定了之后不被重新绑定。可以使用脱字符^将变量固定。该符号很形象,就像钉子一样固定了变量。

iex(2)> a = 1
1
iex(3)> a = 2
2
iex(5)> ^a = 3
** (MatchError) no match of right hand side value: 3
iex(5)> a
2
iex(6)>

忽略绑定

变量可以重新绑定,也可以固定绑定,当然还可以忽略绑定。与其他语言例如python,swift类似。Elixir可以使用下划线_忽略变量的绑定。

iex(6)> [1, a] = [1, 2]
[1, 2]
iex(7)> a
2
iex(8)> [1, _] = [1, 2]
[1, 2]

_就像占位符一样,虽然它总是能匹配成功,例如可以匹配任何值,可是它并不会绑定任何值。这个功能就是可以在模式匹配中,忽略一些不需要绑定的变量。

总结

以上就是模式匹配的基础内容。需要重新理解=符号的含义,理解匹配这个过程。匹配的过程类似数学表达式的求值过程。

整个过程又和纯数学表达式求值有差别,因为模式只能放在左边,并左右的结构和类型都要一模一样。右边如果出现变量和表达式,则会先对右边的变量或表达式先求值。然后再和左边的模式进行匹配运算。

如果匹配成功,则对左边的模式(变量)进行变量绑定。一次模式匹配只能绑定一次变量。不同的模式匹配可以重新绑定变量。可以使用脱字符^不让变量重新绑定,亦可以使用_忽略绑定。

模式匹配介绍完毕,这个概念存在于很多函数式编程语言中。刚开始可能很不习惯,觉得和赋值没有差别。只要重新认识清楚数学上的等号的含义,就能慢慢的理解。当然实战才是根本,后面的将会使用到模式匹配,到时心中的疑问将会逐步解开。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容