如何通过键从键获取值,无论 - 键是字符串还是原子?

时间:2016-10-11 09:59:04

标签: elixir

是否有任何原生的灵丹妙药方法允许我通过键从地图获取值,无论键是原子还是字符串?像:

a = %{ k: 1 }
b = %{ "k" => 1 }

pure_elixir_method(a, :k) => 1 
pure_elixir_method(b, :k) => 1

2 个答案:

答案 0 :(得分:3)

通过定义特定的protocol

,可以实现所需的行为
defprotocol IndifferentAccess do
  def get(data, key)
end

defimpl IndifferentAccess, for: Map do
  def get(data, key) when is_binary(key) do
    case Map.fetch(data, key) do
      {:ok, value} -> value
      :error ->
        case Map.fetch(data, String.to_atom(key)) do
          {:ok, value} -> value
          :error -> :error
        end
      end
    end
  end
  def get(data, key) when is_atom(key) do
    case Map.fetch(data, key) do
      {:ok, value} -> value
      :error -> get(data, Atom.to_string(key))
    end
  end
end

a = %{ k: 1 }
b = %{ "k" => 1 }
a |> IndifferentAccess.get(:k)
#⇒ 1
b |> IndifferentAccess.get(:k)
#⇒ 1

但我不会这样做。

答案 1 :(得分:3)

没有。

但你可以编写自己的包装方法来做到这一点:

defmodule MyMap do
  def get(map, key) when is_atom(key) do
    Map.get(map, key) || Map.get(map, to_string(key))
  end
end

像这样使用:

map = %{:a => 1, "b" => 2}

MyMap.get(map, :a)     # => 1
MyMap.get(map, :b)     # => 2

1.只因为你可以,并不意味着你应该这样做。 %{k: 1, "k" => 2}是一个很好的例子,为什么你不应该这样做(特别是对于你不了解的数据)。 功能

2.此方法仅适用于atom个键参数,您可以对其进行修改,使其接受原子和字符串参数:MyMap.get(map, "a") # => 1 功能

3.如果您真的想使用原子获取地图值,请考虑在开始时对地图的键进行符号化。查看我的ExUtils.Map.symbolize_keys/2。如果您想自己实施,可以get the code here