【问题标题】:Optional default value for get_in Access behavior elixirget_in 访问行为长生不老药的可选默认值
【发布时间】:2018-07-24 16:28:06
【问题描述】:

是否有在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"], [])

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

更新

感谢@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"]
)

【问题讨论】:

    标签: elixir phoenix-framework


    【解决方案1】:

    您可以为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 参数更灵活,可以在不同场景中重复使用)。

    【讨论】:

    • 这是解决此问题的一种优雅方法,谢谢。它将在 Phoenix 1.3 应用程序中的什么位置存在?寻找添加它的最佳位置。这也算是协议吗?
    • 不,它不是协议,因为协议适用于特定的数据结构,我们不会以某种方式覆盖访问协议 :) 对于这样的事情,我有 helpers 目录,它位于 lib,而不是lib/web.
    • 很高兴知道。这个功能在 Phoenix 应用程序中的什么位置?有什么建议吗?
    • 检查我编辑的评论。我使用helpers 目录,因为它是通用功能,可以在任何地方应用,并且不处理业务逻辑。
    • 完美的解释了它:)
    【解决方案2】:

    另一种方式,您可以使用|| 运算符(doc)。

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

    所以如果get_in 返回 nil,[] 将像默认值一样被选择

    【讨论】:

      【解决方案3】:

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

      类似这样的:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-01
        • 2019-11-29
        • 1970-01-01
        • 1970-01-01
        • 2010-09-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多