【问题标题】:get_in for nested list & struct in elixir长生不老药中嵌套列表和结构的get_in
【发布时间】:2016-10-04 14:51:18
【问题描述】:

我有一个结构

s = [
  a: %Bla{
   b: "c"
  }
]

我想从中获取c 值。我正在努力做

get_in(s, [:a, :b])

但它并非旨在从结构中获取价值。是否有任何类似物可以让我使用嵌套结构从列表中获取c

【问题讨论】:

  • get_in(s, [:a, :b]) #=> "c" 我。
  • 废话!让我调查一下为什么它对我不起作用
  • @Dogbert 更新了问题。结构很重要!

标签: elixir


【解决方案1】:

作为documentedget_in 默认情况下不适用于结构:

Access 语法 (foo[bar]) 不能用于访问结构中的字段,因为默认情况下结构不实现 Access 行为。这也是设计决策:动态访问查找旨在用于动态键值结构(如映射和关键字),而不是用于静态结构(如结构)。

有两种方法可以实现你想要的:

  1. 为您的结构实现Access 行为。

  2. 使用Access.key(:foo) 而不是:foo

我会使用 (2):

iex(1)> defmodule Bla do
...(1)>   defstruct [:b]
...(1)> end
iex(2)> s = [a: %Bla{b: "c"}]
[a: %Bla{b: "c"}]
iex(3)> get_in(s, [:a, Access.key(:b)])
"c"

【讨论】:

  • Access.key(:foo) 表示如果您使用get_in(nil, [Access.key(:foo)]),它将抛出一个 BadMapError 而不是返回nil :(
【解决方案2】:

这是我的 try 函数版本,用于从映射和结构返回值:

def try(map, keys) do
  Enum.reduce(keys, map, fn key, acc -> 
    if acc, do: Map.get(acc, key) 
  end)
end

【讨论】:

    【解决方案3】:

    这是我的回复,它对遇到的非映射值更加宽容,例如中间遍历值为零字符串或Map.get() 会抱怨的其他东西

    这本质上是Kernel.get_in/2 的一个更宽容的版本。如果缺少任何键,或者如果在中间遍历它得到一个非映射的东西,它将返回 nil。

        @spec key_getter(map(), list(atom() | String.t())) :: any() | nil
        def key_getter(nil, _), do: nil
        def key_getter(map_or_struct, []), do: map_or_struct
        def key_getter(map_or_struct, _) when not is_map(map_or_struct), do: nil
    
        def key_getter(map_or_struct, [next_key | keys]),
          do: key_getter(Map.get(map_or_struct, next_key, nil), keys)
    

    【讨论】:

      猜你喜欢
      • 2016-08-03
      • 2020-12-08
      • 2018-07-24
      • 2016-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多