【问题标题】:Elixir: best practice to extract data from nested structsElixir:从嵌套结构中提取数据的最佳实践
【发布时间】:2022-03-03 10:06:12
【问题描述】:

在 Elixir 中,我们可以使用

从嵌套数据结构中获取数据
data = %{field: %{other_field: 1}}
data[:field][:other_field]

如果它包含列表,也可以使用

data = %{field: %{other_field: [1]}}
get_in data, [:field, :other_field, Access.at(0)]

但是鉴于 data.field.other_field 是一个结构,如何获取该数据? 以上两种方法都会失败,因为结构没有实现Access.fetch/2

data = %{field: %{other_field: %Struct{a: 1}}}

那么除了模式匹配之外,访问嵌套结构数据的正确方法是什么?

【问题讨论】:

    标签: elixir


    【解决方案1】:

    使用Access.key/2:

    key(key, 默认 \\ nil)

    访问地图/结构中的给定键。

    如果键不存在或访问的值为nil,则使用默认值。

    iex(1)> defmodule Struct do
    ...(1)>   defstruct [:a]
    ...(1)> end
    iex(2)> data = %{field: %{other_field: %Struct{a: 1}}}
    %{field: %{other_field: %Struct{a: 1}}}
    iex(3)> get_in data, [:field, :other_field, Access.key(:a)]
    1
    iex(4)> get_in data, [:field, :other_field, Access.key(:b, :default)]
    :default
    

    【讨论】:

      【解决方案2】:

      为此,我使用了 ruby​​ 的 try 运算符实现。

      @spec try(Access.t(), nonempty_list(node) | atom, term) :: term
      def try(data, keys, default \\ nil)
      
      def try(nil, _keys, default), do: default
      
      def try(data, keys, default) when is_atom(keys) do
        try(data, [keys], default)
      end
      
      def try(data, keys, default) when length(keys) == 1 do
        get_in(data, [Access.key(hd(keys), default)])
      end
      
      def try(data, keys, default) do
        get_in(data, [Access.key(hd(keys))])
        |> try(tl(keys), default)
      end
      

      示例中的用法

      try(data, [:field, :other_field, :a]) # with default nil
      
      try(data, [:field, :other_field, :a], 42) # with default 42
      
      try(data, :single_field_as_atom) # with a single value
      

      【讨论】:

        【解决方案3】:

        AccessibleStructAccess 库中提供了通用实现。

        这允许您使用熟悉的Map 语法。

        data = %Data{field: %{other_field: 1}}
        data[:field][:other_field]
        

        【讨论】:

          猜你喜欢
          • 2016-09-21
          • 2011-08-25
          • 1970-01-01
          • 1970-01-01
          • 2023-04-08
          • 2015-04-26
          • 2020-08-22
          • 1970-01-01
          相关资源
          最近更新 更多