get_in访问行为elixir的可选默认值



是否有一个选项可以在 get_in/2中添加默认的后备值?

方案:

merge_maps = get_in(
  payload, ["msg", "clicks"]
) ++ get_in(
  payload, ["msg", "opens"]
)

如果在嵌套的"msg"地图中找不到键"clicks""opens",则get_in/2将返回nil,然后引发错误:

** (ArgumentError) argument error
    :erlang.++(nil, nil)
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
    (iex) lib/iex/evaluator.ex:250: IEx.Evaluator.handle_eval/5
    (iex) lib/iex/evaluator.ex:230: IEx.Evaluator.do_eval/3
    (iex) lib/iex/evaluator.ex:208: IEx.Evaluator.eval/3
    (iex) lib/iex/evaluator.ex:94: IEx.Evaluator.loop/1
    (iex) lib/iex/evaluator.ex:24: IEx.Evaluator.init/4

能够做

之类的事情真是太好了
get_in(payload, ["msg", "clicks"], [])

如果没有找到该键的值,则空列表将是后备值。实现这一目标的正确方法是什么?

update

感谢@patnowak的答案,我在get_in周围实现了一个包装器:

defmodule Helpers.AccessHelper do
  def get_in_attempt(data, keys, default \ []) do
    case get_in(data, keys) do
      nil -> default
      result -> result
    end
  end
end

然后在另一个文件中:

import Helpers.AccessHelper, only: [get_in_attempt: 2]
merge_maps = get_in_attempt(
  payload, ["msg", "clicks"]
) ++ get_in_attempt(
  payload, ["msg", "opens"]
)

您可以为Kernel.get_in/2编写自己的包装器,但使用默认值作为后备。

def get_in_attempt(data, keys, default) do
  case get_in(data, keys) do
    nil-> default
    result -> result
  end
end

因此,在您的情况下,足以拥有

def get_in_attempt(data, keys) do
  case get_in(data, keys) do
    nil-> [] # your default is set, so don't need to pass it
    result -> result
  end
end

但是,使用第一种方法(使用明确的default参数更灵活,可以在不同的情况下重复使用(。

另一种方式,您可以使用 || operator(doc(。

merge_maps = (get_in(
  payload, ["msg", "clicks"]
) || [] ) ++ ( get_in(
  payload, ["msg", "opens"]
) || [] )

因此,如果 get_in返回nil,则[]将被选为默认值

我认为您想在这种情况下使用Access.key/2Kernel.get_in中的键可以是函数,因此您可以将字符串键列表与访问函数交换(如果找不到键,Access.key/2支持默认值(。

类似的东西:

get_in(payload, ["msg", Access.key("clicks", []))

最新更新