简体   繁体   English

Elixir:如果映射包含至少一个整数键,则模式匹配功能

[英]Elixir : Pattern match a function if a map contains at least one integer key

I want to achieve something like the below (which obviously does not work) 我想要实现类似以下的功能(显然不起作用)

def f1(%{key => _}) when is_integer(key) do :error end
def f1(%{}) do :ok end

I could match a map in the function head and check for an integer key inside the function body. 我可以在函数头中匹配一个映射,并检查函数体内的整数键。 Just wondering if there is a better approach. 只是想知道是否有更好的方法。 Any suggestions? 有什么建议么?

Nope, this can't be done with pattern matching. 不,这不能通过模式匹配来完成。 Here's how I'd implement it using the method you described: 这是我使用您描述的方法实现它的方式:

def f1(%{} = map) do
  if map |> Map.keys() |> Enum.any?(&is_integer/1), do: :error, else: :ok
end

While it's impossible per se, one might slightly improve the performance by generating the clauses when possible integer values are known in advance. 虽然这本身是不可能的,但是当可能的整数值事先已知时,可以通过生成子句来稍微提高性能。 Also, Kernel.map_size/1 , which is allowed in guards, will be required: 另外,将需要在防护中允许使用的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

This example is a bit contrived, but it shows how one fight for the performance when it's really needed. 这个示例有些人为,但是它显示了在真正需要时如何为性能而战。 Macros are expanded by the compiler, so the resulting code would declare 5 different clauses: one for an empty map, three for possible values and the last one for the default execution block. 宏由编译器扩展,因此生成的代码将声明5个不同的子句:一个用于空映射,三个用于可能的值,最后一个用于默认执行块。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM