我想要实现类似以下的功能(显然不起作用)
def f1(%{key => _}) when is_integer(key) do :error end
def f1(%{}) do :ok end
我可以匹配函数头中的映射,并检查函数体内的整数键。只是想知道是否有更好的方法。有什么建议吗?
答案 0 :(得分:1)
不是,这不能通过模式匹配来完成。这是我使用您描述的方法实现的方式:
def f1(%{} = map) do
if map |> Map.keys() |> Enum.any?(&is_integer/1), do: :error, else: :ok
end
答案 1 :(得分:1)
虽然这本身是不可能的,但如果事先知道可能的整数值,则可以通过生成子句来稍微提高性能。另外,还需要Kernel.map_size/1
(在警卫队中允许):
defmodule NoIntegerKeys do
defmacro __using__(name: name, disallowed: enum, do: block) do
[
(quote do: def unquote(name)(%{} = map) when map_size(map) == 0, do: :ok) |
Enum.map(enum, fn i ->
quote do
def unquote(name)(%{unquote(i) => _}), do: :error
end
end)
] ++ [
(quote do: def unquote(name)(%{} = map), do: unquote(block))
]
end
end
defmodule Test do
use NoIntegerKeys, name: :f1, disallowed: [0,1,2], do: :ok
end
Test.f1(%{})
#⇒ :ok
Test.f1(%{foo: :bar})
#⇒ :ok
Test.f1(%{:foo => :bar, 3 => :baz})
#⇒ :ok
# BUT
Test.f1(%{:foo => :bar, 2 => :baz})
#⇒ :error
此示例有些人为设计,但它显示了在真正需要时如何为性能而战。宏由编译器扩展,因此生成的代码将声明5个不同的子句:一个用于空映射,三个用于可能的值,最后一个用于默认执行块。