Elixir:模式匹配对元组和映射的工作方式不同

Posted

技术标签:

【中文标题】Elixir:模式匹配对元组和映射的工作方式不同【英文标题】:Elixir: pattern matching works differently for tuples and maps 【发布时间】:2014-07-04 18:46:30 【问题描述】:

在 Elixir 中,如果我尝试对以下两个元组进行模式匹配:

a = 1, 2

我收到匹配错误。但是如果我对两张地图做同样的事情:

%x: a = %x: 1, y: 2

它工作正常,a 绑定到 1。我可以看到为什么匹配两个元组会出错,但为什么匹配映射不会出错?

【问题讨论】:

不应高于:%x: a = x: 1, y: 2 是:%x: a = %x: 1, y: 2? @ericky 是的,应该,我编辑了。 【参考方案1】:

maps,Elixir 中的主要键值存储,有一个有趣的功能,在模式匹配方面将它们与其他数据结构区分开来。

map 实际上可以仅对值的子集进行模式匹配。模式中的键必须存在于匹配中,但两个结构不必像 listtuple 那样相互镜像。例如:

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

iex(1)> a, b = 1, 2, 3
** (MatchError) no match of right hand side value: 1, 2, 3

iex(1)> %:a => one = %:a => 1, :b => 2, :c =>3
%a: 1, b: 2, c: 3
iex(2)> one
1
iex(3)> %:a => one, :c => three = %:a => 1, :b => 2, :c =>3
%a: 1, b: 2, c: 3
iex(4)> three
3
iex(5)> one
1
iex(6)> % = %:a => 1, :b => 2, :c =>3
%a: 1, b: 2, c: 3
iex(7)> %:d => four = %:a => 1, :b => 2, :c =>3
** (MatchError) no match of right hand side value: %a: 1, b: 2, c: 3

iex(8)> %:a => one, :d => four = %:a => 1, :b => 2, :c =>3
** (MatchError) no match of right hand side value: %a: 1, b: 2, c: 3

如果模式的数据结构与匹配的数据结构(即大小)不同,我们可以看到listtuple 都不匹配。而地图并非如此。因为模式和匹配中都存在密钥,所以匹配成功,无论模式和匹配的大小不同。空的map 也会匹配。

但是,如果模式中的键不在匹配中,则匹配不会成功。即使有匹配的键也是如此。因此,模式中使用的任何键都必须存在于匹配中。

您将在 Phoenix 框架中广泛看到这种匹配,以仅从请求中获取必要的参数。

来源:-Notes on Elixir: Pattern-Matching Maps

【讨论】:

【参考方案2】:

在第一个示例中,您尝试将单个元素元组与两个元素元组进行匹配。在第二个示例中,您将匹配左右映射中的 :x 键。

编辑:我应该澄清 Elixir 中数据结构和模式匹配的规则。

在元组上进行匹配时,您需要提供一个匹配整个元组结构的模式。您可以使用_,这是“catch-all”模式,但您仍然需要为元组的所有元素提供它。在列表上匹配时,您必须使用[a, b, c] = [1, 2, 3] 语法匹配所有元素,或者使用[h|t] = [1, 2, 3] 语法匹配头部和尾部。但是,在匹配映射时,您可以匹配映射中的一个或多个键,这为您提供了%a: b = %a: :foo, b: :bar 语法。

数据结构之间的语义有点不同,但都是相当常识的。元组规则的存在是因为两个元组不能相同,除非它们具有相同数量的元素,列表具有相同的限制,但是由于列表的语义,访问列表的头元素是使用时最常见的操作他们,因此[h|t] 语法。但是 Map 可以根据特定的键进行匹配,因此元素的数量无关紧要,只要匹配的双方包含相同的键,并且值的可选模式,那么它就是成功的匹配。

【讨论】:

我明白了。需要明确的是,地图是唯一允许部分模式匹配的数据结构? 是的,没错。其他一切都需要模式来匹配整个结构。

以上是关于Elixir:模式匹配对元组和映射的工作方式不同的主要内容,如果未能解决你的问题,请参考以下文章

Python结构模式匹配中如何区分元组和列表?

如何根据某些文本标准对元组列表进行分组/存储?

如何在 Python 中对元组列表列表进行平面映射? [复制]

python 数组和列表的区别

Elixir 列表模式匹配 ~ 在使用列表模式匹配常量后得到 x

python 元组操作总结