简体   繁体   English

如何在elixir的函数头中的映射键上进行模式匹配

[英]How to do pattern matching on map keys in function heads in elixir

I can't seem to find a way to pattern match on a map's key in a function head.我似乎找不到在函数头中的地图键上进行模式匹配的方法。 Is there a way to do this?有没有办法做到这一点? What I'm trying to do is run different code depending on whether a certain key already exists in a map or not (and also wanted to avoid if/else and the like)我想要做的是根据地图中是否已经存在某个键来运行不同的代码(并且还想避免 if/else 等)

This is what my code looks like这就是我的代码的样子

def my_func(key, %{key => _} = map), do: ...

which gives me this error这给了我这个错误

** (CompileError) illegal use of variable key inside map key match, maps can only match on existing variable by using ^key ** (CompileError) 在映射键匹配中非法使用变量键,映射只能通过使用 ^key 匹配现有变量

Of course I also tried it using the ^当然我也尝试过使用^

def my_func(key, %{^key => _} = map), do: ...

which then gives然后给出

** (CompileError) unbound variable ^key ** (CompileError) 未绑定变量 ^key

I'm using elixir 1.3.1/erlang 19.0 x64 on a windows 8.1 machine.我在 Windows 8.1 机器上使用 elixir 1.3.1/erlang 19.0 x64。 Thanks for reading!感谢阅读!

You can try several approaches depending on the specific problem and the Elixir version you're using:您可以根据具体问题和您使用的 Elixir 版本尝试多种方法:

  • Map pattern matching地图模式匹配
  • Checking a given key exists (Elixir < 1.10)检查给定的密钥是否存在(Elixir < 1.10)
  • Checking a given key exists (Elixir >= 1.10)检查给定密钥是否存在(Elixir >= 1.10)

Map pattern matching地图模式匹配

If you can just pattern match with the key you need:如果您只能与您需要的密钥进行模式匹配:

defmodule Test do
  def my_func(%{"a" => value}), do: {:a, value}
  def my_func(%{"b" => value}), do: {:b, value}
  def my_func(_), do: :error
end

Then in IEx:然后在 IEx 中:

iex(1)> Test.my_func(%{"a" => 1})
{:a, 1}
iex(2)> Test.my_func(%{"b" => 2})
{:b, 2}

Also order of the clauses are important eg if you are trying to match %{"b" => 2} but you have the following map %{"a" => 1, "b" => 2} , the key "a" will match first, because is in the first clause:子句的顺序也很重要,例如,如果您尝试匹配%{"b" => 2}但您有以下映射%{"a" => 1, "b" => 2} ,键"a"将首先匹配,因为在第一个子句中:

iex(3)> Test.my_func(%{"a" => 1, "b" => 2})
{:a, 1}

If you want to generate something for every key you can match, I recommend a different approach.如果你想为你可以匹配的每个键生成一些东西,我推荐一种不同的方法。 For example, if you want to map a function to those keys:例如,如果要将函数映射到这些键:

defmodule Test0 do
  def my_op({"times_2", value}), do: {"times_2", value * 2}
  def my_op({"times_3", value}), do: {"times_3", value * 3}
  def my_op({key, value}), do: {key, value}

  def my_func(m) do
    Enum.map(m, &my_op/1) |> Enum.into(%{})
  end
end

So you would get the following:所以你会得到以下信息:

iex(1)> Test0.my_func(%{"times_2" => 2, "times_3" => 3, "whatever" => 42})
%{"times_2" => 4, "times_3" => 9, "whatever" => 42}

Checking a given key exists (Elixir < 1.10)检查给定的密钥是否存在(Elixir < 1.10)

You cannot pattern match a key to a variable.您不能将键与变量进行模式匹配。 The problem is the compiler needs to generate code to search for something it doesn't know yet.问题是编译器需要生成代码来搜索它还不知道的东西。 When you pattern match you usually give the compiler some hints of what it'll receive.当您进行模式匹配时,您通常会给编译器一些它将接收到的提示。 For keys in maps the hint is the key itself.对于映射中的键,提示是键本身。 In this case, even pointing that the first argument should be the key to look for, it is not enough for the compiler.在这种情况下,即使指出第一个参数应该是要查找的关键,对于编译器来说也是不够的。 So your approach should be to use an if statement:所以你的方法应该是使用 if 语句:

defmodule Test1 do
  def my_func(k, m) do
    if Map.has_key?(k, m) do
      ... do something when key is found ...
    else
      ... do something when key is not found ...
    end
  end
end

Checking a given key exists (Elixir >= 1.10)检查给定密钥是否存在(Elixir >= 1.10)

Elixir 1.10 adds the guard is_map_key/2 that can be used to solve this problem finally! Elixir 1.10 is_map_key/2增加了可以用来解决这个问题的守卫is_map_key/2

defmodule Test2 do
  def my_func(key, map) when is_map_key(map, key) do
    ... key is found ...
  end

  def my_func(_, _) do
    ... key is not found ...
  end
end

This will definitely solve the compilation issue :)这肯定会解决编译问题:)

I hope this answers your question.我希望这能回答你的问题。

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

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