#elixir
#elixir
Вопрос:
У меня есть структура
s = [
a: %Bla{
b: "c"
}
]
Я хочу извлечь c
из него значение. Я пытаюсь сделать
get_in(s, [:a, :b])
Но он не предназначен для получения значения из структуры. Есть ли какой-либо аналог, который позволяет мне извлекать c
данные из списка с помощью вложенной структуры?
Комментарии:
1.
get_in(s, [:a, :b]) #=> "c"
для меня.2. Дерьмо! Позвольте мне выяснить, почему это не работает на моей стороне
3. @Dogbert обновил вопрос. Структура имеет значение!
Ответ №1:
Как задокументировано, get_in
по умолчанию не работает со структурами:
Синтаксис доступа (foo[bar]) не может использоваться для доступа к полям в структурах, поскольку структуры не реализуют поведение доступа по умолчанию. Это также дизайнерское решение: динамический поиск доступа предназначен для динамических структур ключ-значение, таких как карты и ключевые слова, а не для статических, таких как структуры.
Есть два способа добиться того, чего вы хотите:
-
Реализуйте
Access
поведение для вашей структуры. -
Используйте
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"
Комментарии:
1.
Access.key(:foo)
означает, что если вы используетеget_in(nil, [Access.key(:foo)])
его, он выдаст ошибку, а не вернетnil
🙁
Ответ №2:
Вот моя версия try
функции для возврата значений как из maps, так и из structs:
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)