Как использовать переменную для ссылки на ключ структуры?

elixir

1492 просмотра

3 ответа

Как я могу использовать переменную для доступа к полю структуры:

  var1 = "key1"
  struct1 = %MyStruct{key1: "fdsfd", key2: 33}

  val1 = struct1[:????] # how to use var1 for "key1"?
Источник Размещён: 08.11.2019 11:30

Ответы (3)


7 плюса

Решение

Используйте String.to_existing_atom/1и Map.get/2(поскольку структуры на самом деле являются картами):

iex(1)> defmodule MyStruct do
...(1)>   defstruct [:key1, :key2]
...(1)> end
iex(2)> var1 = "key1"
"key1"
iex(3)> struct1 = %MyStruct{key1: "fdsfd", key2: 33}
%MyStruct{key1: "fdsfd", key2: 33}
iex(4)> val1 = Map.get(struct1, String.to_existing_atom(var1))
"fdsfd"

[:key]Синтаксис не будет работать с структурами по умолчанию , так как он использует Accessпротокол , который должен быть реализован пользователем для каждой структуры.

String.to_existing_atom/1выдаст ошибку, если атом еще не существует, но его безопаснее использовать, чем преобразование произвольного ввода в атом, и он обязательно будет существовать, если у вас есть структура с уже определенным ключом. Смотрите этот вопрос для более подробной информации.

Автор: Dogbert Размещён: 20.08.2016 03:40

2 плюса

Кроме того Map.get/2, вы можете использовать сопоставление с шаблоном, чтобы получить значение, или реализовать поведение Access в своей структуре, чтобы вы могли использовать ее так, struct1[var1]как вы пытались.

(Превратите свой var1 = "key1"атом в атом, String.to_existing_atom/1как предложено.)

Учитывая struct1 = %MyStruct{key1: "fdsfd", key2: 33}

Сопоставление с образцом:

iex> %{^var1 => value} = struct1
iex> value
"fdsfd"

Поведение доступа:

defmodule MyStruct do
  defstruct key1: nil, key2: nil

  def fetch(my_struct, key) do
    {:ok, Map.get(my_struct, key)}
  end
end

iex> my_struct[var1]
"fdsfd"

Обратите внимание, что я не реализовал полное поведение доступа. См. Http://elixir-lang.org/docs/stable/elixir/Access.html#callbacks

Автор: Martin Svalin Размещён: 20.08.2016 09:13

1 плюс

Если вы используете Elixir 1.3 или новее, вы можете использовать Access.key!with get_inв любой структуре:

var1 = "key1"
struct1 = %MyStruct{key1: "fdsfd", key2: 33}

val1 = get_in struct1, [Access.key!(String.to_existing_atom(var1))]

До Elixir 1.3 не было возможности использовать get_in/3(где путь поиска переменный), и вы могли использовать только get_in/2как val1 = get_in struct1.var1. Access.key!имеет преимущество работы или повышения KeyError.

Автор: Luke Imhoff Размещён: 21.08.2016 11:29
Вопросы из категории :
32x32