我正在玩模式匹配,我发现,将方法的匹配参数与空映射进行模式化并不容易。我认为它会是这样的:
defmodule PatternMatch do
def modify(%{}) do
%{}
end
def modify(map) do
# expensive operation
%{ modified: "map" }
end
end
但似乎第一个函数子句匹配任意映射:
iex> PatternMatch.modify(%{a: "map"})
==> %{}
还有另一种检查空地图的方法吗?
答案 0 :(得分:72)
它通过设计以这种方式工作,但不可否认,乍一看它可能有点令人困惑。此功能允许您使用模式匹配来解构地图,而无需指定所有键。例如:
iex> %{b: value} = %{a: 1, b: 2, c: 3}
%{a: 1, b: 2, c: 3}
iex> value
2
因此,%{}
将匹配任何地图。如果要匹配函数中的空映射,则必须使用保护子句:
defmodule PatternMatch do
def modify(map) when map == %{} do
%{}
end
def modify(map) do
# ...
end
end
答案 1 :(得分:22)
除了@ PatrickOscity的答案(我将用于空地图),您可以使用map_size/1警卫来匹配具有多个键的地图:
defmodule PatternMatch do
def modify(map) when map_size(map) == 0 do
%{}
end
def modify(map) when map_size(map) == 1 do
#something else
end
def modify(map) do
# expensive operation
%{ modified: "map" }
end
end
以下是iex使用Kernel.match?/2
显示map_size/1
的输出结果:
iex(6)> Kernel.match?(map when map_size(map) == 1, %{})
false
iex(7)> Kernel.match?(map when map_size(map) == 1, %{foo: "bar"})
true
答案 2 :(得分:0)
除了目前为止提供的所有很酷的答案,您还可以考虑使用看似帽子或上箭头的unary pin operator。您可以使用它为变量添加前缀,以确保模式与其值匹配,如相关文档中所述:
如果要对a进行模式匹配,请使用pin运算符^ 现有变量的值而不是重新绑定变量
以下是一个例子:
defmodule A do
def determine_map_volume(some_map) do
an_empty_map = %{}
some_map
|> case do
^an_empty_map -> :empty # Application of pin operator
_ -> :not_empty
end
end
end
您可以按如下方式验证:
A.determine_map_volume(%{})
:empty
A.determine_map_volume(%{a: 1})
:not_empty
您打算使用哪种方法取决于您的个人/组织偏好,以确保代码的可读性。