В Elixir, как вы инициализируете структуру с помощью переменной карты
Я знаю, что можно создать структуру через %User{ email: 'blah@blah.com' }
, Но если бы у меня была переменная params = %{email: 'blah@blah.com'}
Есть ли способ создать эту структуру, используя эту переменную, например, для %User{ params }
,
Это дает ошибку, просто интересно, можно ли ее взорвать или как-то еще?
3 ответа
Вы должны использовать 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"}
Предыдущие ответы оба хороши, с одной оговоркой: ключи в структуре - это атомы, ключи в вашем хэше могут быть строками. Использование метода 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-группе по эликсиру-языку от самого Хосе:
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
Еще один способ сделать это с помощью Map.merge/2
:
Пример:
params
#=> %{email: "blah@blah.com"}
%User{} |> Map.merge(params)
#=> %User{ email: 'blah@blah.com' }