2017-02-01 1 views
1

Я пытаюсь конвертировать карты на структуру следующим образом:Преобразование карты на структуру

У меня есть карта:

iex(6)> user      
%{"basic_auth" => "Basic Ym1hOmphYnJhMTc=", "firstname" => "foo", 
    "lastname" => "boo"} 

Значение должно быть применено к структуре:

iex(7)> a = struct(UserInfo, user) 
%SapOdataService.Auth.UserInfo{basic_auth: nil, firstname: nil, lastname: nil} 

As вы можете видеть, значения struct nil, почему?

+0

http://stackoverflow.com/questions/30927635/in-elixir-how-do-you-initialize-a-struct-with-a-map-variable – sobolevn

+0

@sobolevn Это именно то, что пытался ОП. Как предположил JustMichael, это не работает, потому что карта имеет строковые ключи. –

ответ

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 м, достигая глобального предела Atom.

2

Мое дикое предположение, что это не работает, потому что у вас есть ключи как строки на карте и как атомы в структуре.

2

Вы можете попробовать exconstructor. Он делает именно то, что вам нужно.

Вот небольшой пример:

defmodule TestStruct do 
    defstruct field_one: nil, 
      field_two: nil, 
      field_three: nil, 
      field_four: nil 
    use ExConstructor 
end 

TestStruct.new(%{"field_one" => "a", "fieldTwo" => "b", :field_three => "c", :FieldFour => "d"}) 
# => %TestStruct{field_one: "a", field_two: "b", field_three: "c", field_four: "d"} 

Ссылка на документацию: http://hexdocs.pm/exconstructor/ExConstructor.html

1

Я хотел бы использовать ревизии экто для этого:

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 

хорошая вещь об этом использовании экто является то, что вы также имеет дополнительные преимущества, такие как проверка и вам не нужно волновать поля на карте, это строки или атомы.

+0

супер классное решение – simo