我正在尝试将地图转换为结构如下:
我有一张地图:
iex(6)> user
%{"basic_auth" => "Basic Ym1hOmphYnJhMTc=", "firstname" => "foo",
"lastname" => "boo"}
该值应该应用于struct:
iex(7)> a = struct(UserInfo, user)
%SapOdataService.Auth.UserInfo{basic_auth: nil, firstname: nil, lastname: nil}
如您所见,struct的值为nil,为什么?
答案 0 :(得分:2)
答案 1 :(得分:2)
您可以尝试exconstructor。它完全符合您的需求。
这是一个小例子:
<controls:BranchFilter Grid.Row="0" BranchId="0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="BranchChanged">
<i:InvokeCommandAction Command="{Binding LoadItems}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</controls:BranchFilter>
答案 2 :(得分:2)
要扩展JustMichael的答案,您可以先使用String.to_existing_atom/1
将密钥转换为原子,然后使用Kernel.struct/2
来构建结构:
user_with_atom_keys = for {key, val} <- user, into: %{} do
{String.to_existing_atom(key), val}
end
user_struct = struct(UserInfo, user_with_atom_keys)
# %UserInfo{basic_auth: "Basic Ym1hOmphYnJhMTc=", firstname: "foo",
lastname: "boo"}
请注意,这会使用String.to_existing_atom/1
来阻止VM达到全局Atom限制。
答案 3 :(得分:2)
我会使用Ecto的变更集:
defmodule UserInfo do
use Ecto.Schema
schema "user_info" do
field :basic_auth, :string
field :firstname, :string
field :lastname, :string
end
end
然后在你的代码中的某个地方
import Ecto.Changeset
user_struct = cast(%UserInfo{},
your_user_map,
UserInfo.__schema__(:fields))
|> apply_changes
使用ecto的好处在于你还有额外的好处,比如验证,你不必担心地图中的字段是字符串或原子。
答案 4 :(得分:0)
%{"basic_auth" => "Basic Ym1hOmphYnJhMTc=", "firstname" => "foo", "lastname" => "boo"}
|> Poison.encode
|> (fn {:ok, json} -> json end).()
|> Poison.decode(as: %SapOdataService.Auth.UserInfo{})
或
~S({"basic_auth":"Basic Ym1hOmphYnJhMTc=","firstname":"foo","lastname":"boo"})
|> Poison.decode(as: %SapOdataService.Auth.UserInfo{})
请注意,这不会与@enforce_keys
上的UserInfo
一起编译。