%User{ email: '[email protected]' }
を介して構造体を作成できることは知っています。しかし、変数params = %{email: '[email protected]'}
がある場合、たとえば%User{ params }
などの変数を使用してその構造体を作成する方法があります。
これはエラーになりますが、それを爆発させることができるのか、それとも何か他の方法があるのでしょうか?
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"}
前の答えはどちらも良いですが、1つの警告があります。構造体のキーはアトムであり、ハッシュのキーは文字列である可能性があります。 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"}
Jose自身のelixir-lang-talk Googleグループでこれを見つけました。
https://groups.google.com/d/msg/elixir-lang-talk/6geXOLUeIpI/L9einu4EEAAJ
これは、1回のパスですべてを実行できることを除いて、ほとんどの方法です。
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: "[email protected]"}
%User{} |> Map.merge(params)
#=> %User{ email: '[email protected]' }