В Elixir, как вы инициализируете структуру с помощью переменной карты
Я знаю, что можно создать структуру через %User{ email: '[email protected]' }
. Но если бы у меня была переменная params = %{email: '[email protected]'}
, то был бы способ создать эту структуру, используя эту переменную, например, %User{ params }
.
Это дает ошибку, просто интересно, можете ли вы взорвать ее или каким-либо другим способом?
Ответы
Ответ 1
Вы должны использовать функцию struct/2
. Из документов:
defmodule User do
defstruct name: "john"
end
struct(User)
#=> %User{name: "john"}
opts = [name: "meg"]
user = struct(User, opts)
#=> %User{name: "meg"}
struct(user, unknown: "value")
#=> %User{name: "meg"}
Ответ 2
Предыдущие ответы оба хороши, с одной оговоркой: ключи в структуре являются атомами, ключи в вашем хеше могут быть строками. Использование метода struct() будет копировать только по ключам, которые соответствуют, и строки не будут соответствовать атомам. Пример:
defmodule User do
defstruct name: "john"
end
opts = %{"name" => "meg"}
user = struct(User, opts)
#=> %User{name: "john"}
Использование слияния также нечетно, потому что оно "отменит" структуру структуры Карты:
user = Map.merge(%User{}, opts)
#=> %{:__struct__ => User, :name => "john", "name" => "meg"}
Нашел это в группе Google elixir-lang-talk от самого Хосе:
https://groups.google.com/d/msg/elixir-lang-talk/6geXOLUeIpI/L9einu4EEAAJ
Это в значительной степени способ, за исключением того, что вы можете сделать все за один проход:
def to_struct(kind, attrs) do
struct = struct(kind)
Enum.reduce Map.to_list(struct), struct, fn {k, _}, acc ->
case Map.fetch(attrs, Atom.to_string(k)) do
{:ok, v} -> %{acc | k => v}
:error -> acc
end
end
end
Ответ 3
Другой способ сделать это с помощью Map.merge/2
:
merge (map1, map2)
Пример:
params
#=> %{email: "[email protected]"}
%User{} |> Map.merge(params)
#=> %User{ email: '[email protected]' }