Эликсир - прописные ключи в структурах

Я пытаюсь написать клиент CLI в Elixir для API, чтобы я мог войти в систему API, получить данные, необходимые для моих расчетов, а затем выйти из системы. Я определил структуру Packet.Login, которая должна быть моей внутренней структурой данных, которую я получаю после анализа JSON, который я получаю.

Я использую Poison для анализа JSON. Проблема в том, что из-за того, что API возвращает заглавные свойства, я не могу сопоставить их при печати или разборе, поскольку Poison вернет карту с этими заглавными ключами. Проблема в том, что мне кажется невозможным использовать псевдоним, подобный этому. Если я попытаюсь использовать другой синтаксис,

packet[:Token]

это все еще не работает и вместо этого дает мне ошибку. Но в этот раз о Packet.Login не реализовано поведение Access. Я могу понять эту часть, но не первый вопрос. И я пытаюсь сделать код глупым простым.

defmodule Packet.Login do
  defstruct [:Data, :Token]
end

defimpl String.Chars, for: Packet.Login do
  def to_string(packet) do
    "Packet:\n---Token:\t\t#{packet.Token}\n---Data:\t#{packet.Data}"
  end
end

loginPacket = Poison.decode!(json, as: %Packet.Login{})
IO.puts "#{loginPacket}"

При попытке скомпилировать выше, я получаю это:

** (CompileError) lib/packet.ex:31: invalid alias: "packet.Token". If you wanted to define an alias, an alias must expand to an atom at compile time but it did not, you may use Module.concat/2 to build it at runtime. If instead you wanted to invoke a function or access a field, wrap the function or field name in double quotes
(elixir) expanding macro: Kernel.to_string/1

Есть ли способ для меня это как-то исправить? Я думал о разборе карты и обнулении всех полей в первую очередь, но я бы не хотел.

Почему я не могу использовать заглавные буквы для структуры? Похоже, что я могу, пока я не пытаюсь использовать их.

1 ответ

Решение

Чтобы получить доступ к полю карты, представляющему собой атом, начинающийся с заглавной буквы, вам необходимо либо поместить ключ в кавычки, например: foo."Bar" или используйте синтаксис скобок, например foo[:Bar], foo.Bar в эликсире разбирается как псевдоним. Со структурами вы не можете использовать синтаксис скобок, поэтому проще всего использовать кавычки вокруг имени поля. Поэтому в вашем коде вам нужно изменить:

"Packet:\n---Token:\t\t#{packet.Token}\n---Data:\t#{packet.Data}"

чтобы:

"Packet:\n---Token:\t\t#{packet."Token"}\n---Data:\t#{packet."Data"}"

Я нигде не смог найти документально подтвержденного, но источник в Elixir упоминает об этом в некоторых местах, а также использует этот синтаксис для доступа к некоторым функциям в :erlang которые имеют имена, которые не являются действительными идентификаторами в Elixir, например :erlang."=<",


Интересный факт: вы можете определить функции в Elixir, которые можно вызывать только с помощью этого синтаксиса цитаты:

iex(1)> defmodule Foo do
...(1)>   def unquote(:"!@#")(), do: :ok
...(1)> end
iex(2)> Foo."!@#"()
:ok
Другие вопросы по тегам